前言
前段时间帮一个家电厂做洗衣机控制板的方案,从水位检测到变频电机驱动,各种洗涤模式的逻辑都过了一遍。说实话,现代洗衣机的功能比想象中复杂得多,光洗涤模式就有十几种,每种模式背后都是一套精细的控制算法。
今天把洗衣机控制系统的技术细节整理出来,从硬件到软件,从传感器到执行器,希望能帮到对家电控制感兴趣的朋友。
系统整体架构
┌─────────────────────────────────────────────────────────────────────────────┐
│ 智能洗衣机控制系统架构 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 用户交互层 │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ 触摸屏/ │ │ 旋钮 │ │ WiFi/ │ │ │
│ │ │ LED显示 │ │ 按键 │ │ 蓝牙模块 │ │ │
│ │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ │
│ └──────────┼────────────────┼────────────────┼────────────────────────┘ │
│ │ │ │ │
│ └────────────────┴────────┬───────┘ │
│ │ │
│ ┌────────────────────────────────────┴────────────────────────────────┐ │
│ │ 主控MCU (STM32/ESP32) │ │
│ │ │ │
│ │ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ │ │
│ │ │ 洗涤模式 │ │ 安全保护 │ │ 故障诊断 │ │ 通信管理 │ │ │
│ │ │ 状态机 │ │ 模块 │ │ 模块 │ │ 模块 │ │ │
│ │ └───────────┘ └───────────┘ └───────────┘ └───────────┘ │ │
│ └────────────────────────────────────┬────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────────────┼──────────────────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ │ 传感器层 │ │ 执行器层 │ │ 电源管理 │
│ │ │ │ │ │ │
│ │ - 水位传感器 │ │ - 变频电机 │ │ - AC/DC转换 │
│ │ - 温度传感器 │ │ - 进水阀 │ │ - 继电器驱动 │
│ │ - 门锁检测 │ │ - 排水泵 │ │ - 过流保护 │
│ │ - 振动传感器 │ │ - 加热器 │ │ │
│ │ - 浊度传感器 │ │ - 门锁电机 │ │ │
│ │ - 称重传感器 │ │ - 蜂鸣器 │ │ │
│ └───────────────┘ └───────────────┘ └───────────────┘
│ │
└─────────────────────────────────────────────────────────────────────────────┘
硬件配置(典型滚筒洗衣机):
- 主控: STM32F103/ESP32
- 电机: BLDC变频电机 (300-1400rpm)
- 加热器: 1800-2000W PTC/电热管
- 进水阀: 2个电磁阀 (冷水/热水)
- 排水泵: 30-40W
- 水位传感器: 气压式
- 温度传感器: NTC 10K
传感器系统
水位检测
c
/**
* 水位传感器 - 气压式原理
*
* 水位上升 → 气压管内气压增大 → 压力传感器检测
* 输出: 频率信号或模拟电压
*/
#include "stm32f1xx_hal.h"
// 水位等级定义 (单位: mm 水柱压力对应值)
typedef enum {
WATER_LEVEL_EMPTY = 0,
WATER_LEVEL_LOW = 120, // 低水位 ~15L
WATER_LEVEL_MEDIUM = 180, // 中水位 ~30L
WATER_LEVEL_HIGH = 240, // 高水位 ~45L
WATER_LEVEL_FULL = 300, // 满水位 ~55L
WATER_LEVEL_OVERFLOW = 350 // 溢出警戒
} WaterLevel_t;
// 水位传感器配置
typedef struct {
uint16_t adc_channel;
uint16_t adc_min; // 空桶ADC值
uint16_t adc_max; // 满水ADC值
uint16_t filter_samples; // 滤波采样数
uint16_t overflow_threshold;
} WaterLevelConfig_t;
// 水位传感器状态
typedef struct {
uint16_t raw_adc;
uint16_t filtered_adc;
uint16_t water_level_mm; // 水位高度 (mm)
float water_volume_L; // 水量 (升)
uint16_t adc_buffer[16]; // 滤波缓冲
uint8_t buffer_index;
} WaterLevelState_t;
static WaterLevelConfig_t water_config = {
.adc_channel = ADC_CHANNEL_0,
.adc_min = 500,
.adc_max = 3500,
.filter_samples = 16,
.overflow_threshold = 3600
};
static WaterLevelState_t water_state;
/**
* 读取水位ADC并滤波
*/
uint16_t water_level_read_filtered(void)
{
// 读取ADC
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 10);
uint16_t adc_value = HAL_ADC_GetValue(&hadc1);
// 滑动平均滤波
water_state.adc_buffer[water_state.buffer_index] = adc_value;
water_state.buffer_index = (water_state.buffer_index + 1) % water_config.filter_samples;
uint32_t sum = 0;
for (int i = 0; i < water_config.filter_samples; i++) {
sum += water_state.adc_buffer[i];
}
water_state.filtered_adc = sum / water_config.filter_samples;
water_state.raw_adc = adc_value;
return water_state.filtered_adc;
}
/**
* ADC转换为水位高度
*/
uint16_t water_level_get_mm(void)
{
uint16_t adc = water_level_read_filtered();
// 线性映射
if (adc <= water_config.adc_min) {
water_state.water_level_mm = 0;
} else if (adc >= water_config.adc_max) {
water_state.water_level_mm = WATER_LEVEL_FULL;
} else {
water_state.water_level_mm = (uint16_t)(
(adc - water_config.adc_min) * WATER_LEVEL_FULL /
(water_config.adc_max - water_config.adc_min)
);
}
return water_state.water_level_mm;
}
/**
* 水位转换为水量 (根据桶形状计算)
* 滚筒洗衣机内筒近似圆柱形
*/
float water_level_get_volume(void)
{
uint16_t level_mm = water_level_get_mm();
// 内筒参数 (典型10kg滚筒)
const float drum_radius = 0.24f; // 内筒半径 240mm
const float drum_length = 0.45f; // 内筒深度 450mm
// 圆柱形水量计算 (简化,实际需考虑倾斜)
// V = L × (R²×arccos((R-h)/R) - (R-h)×√(2Rh-h²))
float h = level_mm / 1000.0f; // 转换为米
float R = drum_radius;
float L = drum_length;
if (h <= 0) return 0;
if (h >= 2 * R) h = 2 * R;
float ratio = (R - h) / R;
if (ratio > 1) ratio = 1;
if (ratio < -1) ratio = -1;
float area = R * R * acosf(ratio) - (R - h) * sqrtf(2 * R * h - h * h);
float volume = area * L * 1000; // 转换为升
water_state.water_volume_L = volume;
return volume;
}
/**
* 检查水位是否达到目标
*/
int water_level_reached(WaterLevel_t target)
{
uint16_t current = water_level_get_mm();
return (current >= target - 10); // 允许10mm误差
}
/**
* 检查是否溢出
*/
int water_level_overflow(void)
{
return (water_state.filtered_adc > water_config.overflow_threshold);
}
温度检测
c
/**
* 温度传感器 - NTC热敏电阻
*
* 典型: 10K NTC (25°C时10KΩ)
* B值: 3950
*/
typedef struct {
uint16_t adc_channel;
float beta; // B值
float r_ref; // 参考电阻 (25°C)
float t_ref; // 参考温度 (K)
float r_series; // 串联电阻
float vref; // 参考电压
} NTCConfig_t;
typedef struct {
uint16_t raw_adc;
float resistance; // 当前电阻值
float temperature; // 温度 (°C)
float filtered_temp; // 滤波后温度
} NTCState_t;
static NTCConfig_t ntc_config = {
.adc_channel = ADC_CHANNEL_1,
.beta = 3950.0f,
.r_ref = 10000.0f, // 10K
.t_ref = 298.15f, // 25°C = 298.15K
.r_series = 10000.0f, // 10K串联电阻
.vref = 3.3f
};
static NTCState_t ntc_water; // 水温传感器
static NTCState_t ntc_heater; // 加热器温度传感器
/**
* 读取NTC温度
*
* 电路: VCC --- R_series --- ADC --- NTC --- GND
*/
float ntc_read_temperature(NTCState_t *ntc, NTCConfig_t *config)
{
// 读取ADC
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 10);
ntc->raw_adc = HAL_ADC_GetValue(&hadc1);
// ADC转电压
float voltage = (ntc->raw_adc / 4096.0f) * config->vref;
// 计算NTC电阻
// V = Vref × Rntc / (Rseries + Rntc)
// Rntc = Rseries × V / (Vref - V)
if (voltage >= config->vref - 0.01f) {
ntc->resistance = 1000000; // 开路
} else if (voltage <= 0.01f) {
ntc->resistance = 0; // 短路
} else {
ntc->resistance = config->r_series * voltage / (config->vref - voltage);
}
// Steinhart-Hart方程简化版 (B参数方程)
// 1/T = 1/T_ref + (1/B) × ln(R/R_ref)
if (ntc->resistance > 0) {
float ln_ratio = logf(ntc->resistance / config->r_ref);
float inv_t = 1.0f / config->t_ref + ln_ratio / config->beta;
ntc->temperature = (1.0f / inv_t) - 273.15f; // 转摄氏度
} else {
ntc->temperature = 150.0f; // 异常高温
}
// 一阶低通滤波
static float alpha = 0.1f;
ntc->filtered_temp = ntc->filtered_temp * (1 - alpha) + ntc->temperature * alpha;
return ntc->filtered_temp;
}
/**
* 读取水温
*/
float get_water_temperature(void)
{
return ntc_read_temperature(&ntc_water, &ntc_config);
}
/**
* 读取加热器温度 (用于过热保护)
*/
float get_heater_temperature(void)
{
return ntc_read_temperature(&ntc_heater, &ntc_config);
}
称重传感器
c
/**
* 称重传感器 - 检测衣物重量
*
* 使用应变片 + HX711 ADC
* 用于自动判断水位和洗涤时间
*/
#include "hx711.h"
typedef struct {
GPIO_TypeDef *dout_port;
uint16_t dout_pin;
GPIO_TypeDef *sck_port;
uint16_t sck_pin;
int32_t offset; // 零点偏移
float scale; // 比例系数 (g/count)
} HX711Config_t;
typedef struct {
int32_t raw_value;
float weight_g; // 重量 (克)
float weight_kg; // 重量 (千克)
uint8_t stable; // 稳定标志
} WeightState_t;
static HX711Config_t hx711_config = {
.dout_port = GPIOB,
.dout_pin = GPIO_PIN_0,
.sck_port = GPIOB,
.sck_pin = GPIO_PIN_1,
.offset = 0,
.scale = 0.5f // 需要标定
};
static WeightState_t weight_state;
/**
* HX711读取原始值
*/
int32_t hx711_read_raw(void)
{
// 等待数据准备好
while (HAL_GPIO_ReadPin(hx711_config.dout_port, hx711_config.dout_pin));
int32_t value = 0;
// 读取24位数据
for (int i = 0; i < 24; i++) {
HAL_GPIO_WritePin(hx711_config.sck_port, hx711_config.sck_pin, GPIO_PIN_SET);
value = value << 1;
HAL_GPIO_WritePin(hx711_config.sck_port, hx711_config.sck_pin, GPIO_PIN_RESET);
if (HAL_GPIO_ReadPin(hx711_config.dout_port, hx711_config.dout_pin)) {
value++;
}
}
// 第25个脉冲设置增益
HAL_GPIO_WritePin(hx711_config.sck_port, hx711_config.sck_pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(hx711_config.sck_port, hx711_config.sck_pin, GPIO_PIN_RESET);
// 符号扩展
if (value & 0x800000) {
value |= 0xFF000000;
}
return value;
}
/**
* 读取衣物重量
*/
float weight_read_kg(void)
{
// 多次采样取平均
int32_t sum = 0;
const int samples = 10;
for (int i = 0; i < samples; i++) {
sum += hx711_read_raw();
HAL_Delay(10);
}
weight_state.raw_value = sum / samples;
weight_state.weight_g = (weight_state.raw_value - hx711_config.offset) * hx711_config.scale;
weight_state.weight_kg = weight_state.weight_g / 1000.0f;
// 稳定性判断
static float last_weight = 0;
weight_state.stable = (fabsf(weight_state.weight_kg - last_weight) < 0.1f);
last_weight = weight_state.weight_kg;
return weight_state.weight_kg;
}
/**
* 根据衣物重量推荐水位
*/
WaterLevel_t weight_recommend_water_level(float weight_kg)
{
if (weight_kg < 2.0f) {
return WATER_LEVEL_LOW;
} else if (weight_kg < 4.0f) {
return WATER_LEVEL_MEDIUM;
} else if (weight_kg < 6.0f) {
return WATER_LEVEL_HIGH;
} else {
return WATER_LEVEL_FULL;
}
}
/**
* 零点校准
*/
void weight_tare(void)
{
int32_t sum = 0;
const int samples = 20;
for (int i = 0; i < samples; i++) {
sum += hx711_read_raw();
HAL_Delay(50);
}
hx711_config.offset = sum / samples;
}
门锁与安全检测
c
/**
* 门锁系统
*
* 电磁门锁 + 门开关检测
*/
typedef enum {
DOOR_STATE_OPEN,
DOOR_STATE_CLOSED,
DOOR_STATE_LOCKED,
DOOR_STATE_ERROR
} DoorState_t;
typedef struct {
GPIO_TypeDef *lock_port;
uint16_t lock_pin;
GPIO_TypeDef *switch_port;
uint16_t switch_pin;
GPIO_TypeDef *feedback_port; // 锁舌到位检测
uint16_t feedback_pin;
} DoorLockConfig_t;
typedef struct {
DoorState_t state;
uint8_t switch_closed; // 门开关状态
uint8_t lock_engaged; // 锁舌到位
uint32_t lock_time; // 上锁时间
uint8_t lock_failed; // 锁定失败标志
} DoorLockState_t;
static DoorLockConfig_t door_config;
static DoorLockState_t door_state;
/**
* 检测门状态
*/
DoorState_t door_get_state(void)
{
// 读取门开关
door_state.switch_closed = !HAL_GPIO_ReadPin(
door_config.switch_port, door_config.switch_pin
);
// 读取锁舌状态
door_state.lock_engaged = !HAL_GPIO_ReadPin(
door_config.feedback_port, door_config.feedback_pin
);
if (!door_state.switch_closed) {
door_state.state = DOOR_STATE_OPEN;
} else if (door_state.lock_engaged) {
door_state.state = DOOR_STATE_LOCKED;
} else {
door_state.state = DOOR_STATE_CLOSED;
}
return door_state.state;
}
/**
* 锁门
*/
int door_lock(void)
{
// 检查门是否关闭
if (!door_state.switch_closed) {
return -1; // 门未关
}
// 启动电磁锁
HAL_GPIO_WritePin(door_config.lock_port, door_config.lock_pin, GPIO_PIN_SET);
door_state.lock_time = HAL_GetTick();
// 等待锁舌到位 (最多3秒)
while (!door_state.lock_engaged &&
(HAL_GetTick() - door_state.lock_time) < 3000) {
door_get_state();
HAL_Delay(100);
}
if (!door_state.lock_engaged) {
// 锁定失败
HAL_GPIO_WritePin(door_config.lock_port, door_config.lock_pin, GPIO_PIN_RESET);
door_state.lock_failed = 1;
return -2;
}
door_state.state = DOOR_STATE_LOCKED;
return 0;
}
/**
* 解锁门
*
* 注意:高温或高速旋转时不能解锁
*/
int door_unlock(float water_temp, int motor_running)
{
// 安全检查
if (water_temp > 55.0f) {
return -1; // 水温过高
}
if (motor_running) {
return -2; // 电机运行中
}
// 释放电磁锁
HAL_GPIO_WritePin(door_config.lock_port, door_config.lock_pin, GPIO_PIN_RESET);
// 等待锁舌释放
HAL_Delay(500);
door_get_state();
if (door_state.lock_engaged) {
return -3; // 解锁失败
}
door_state.state = DOOR_STATE_CLOSED;
return 0;
}
执行器控制
变频电机驱动
c
/**
* BLDC变频电机控制
*
* 滚筒洗衣机使用直驱或皮带传动BLDC电机
* 转速范围: 0-1400 RPM
*/
typedef enum {
MOTOR_DIR_CW, // 顺时针
MOTOR_DIR_CCW, // 逆时针
MOTOR_DIR_STOP
} MotorDirection_t;
typedef struct {
// PWM配置
TIM_HandleTypeDef *htim;
uint32_t channel;
// 方向控制GPIO
GPIO_TypeDef *dir_port;
uint16_t dir_pin;
// 使能控制
GPIO_TypeDef *en_port;
uint16_t en_pin;
// 转速反馈 (霍尔传感器)
TIM_HandleTypeDef *htim_hall;
uint8_t pole_pairs; // 极对数
// PID参数
float kp, ki, kd;
// 限制
uint16_t max_rpm;
uint16_t min_rpm;
float max_accel; // 最大加速度 RPM/s
} MotorConfig_t;
typedef struct {
MotorDirection_t direction;
uint16_t target_rpm;
uint16_t actual_rpm;
float duty_cycle;
// PID状态
float integral;
float last_error;
// 保护状态
uint8_t overcurrent;
uint8_t overtemp;
uint8_t stall;
// 运行统计
uint32_t run_time_ms;
uint32_t start_time;
} MotorState_t;
static MotorConfig_t motor_config;
static MotorState_t motor_state;
/**
* 读取电机转速 (通过霍尔传感器)
*/
uint16_t motor_read_rpm(void)
{
// 读取霍尔脉冲频率
uint32_t hall_freq = __HAL_TIM_GET_COUNTER(motor_config.htim_hall);
__HAL_TIM_SET_COUNTER(motor_config.htim_hall, 0);
// 频率转RPM
// RPM = (freq × 60) / (pole_pairs × 6)
// 6 = 每个电周期的霍尔变化次数
if (hall_freq > 0) {
motor_state.actual_rpm = (hall_freq * 60) / (motor_config.pole_pairs * 6);
} else {
motor_state.actual_rpm = 0;
}
return motor_state.actual_rpm;
}
/**
* PID转速控制
*/
float motor_pid_control(uint16_t target_rpm, uint16_t actual_rpm, float dt)
{
float error = (float)target_rpm - (float)actual_rpm;
// 比例项
float p_term = motor_config.kp * error;
// 积分项 (带限幅)
motor_state.integral += error * dt;
if (motor_state.integral > 100) motor_state.integral = 100;
if (motor_state.integral < -100) motor_state.integral = -100;
float i_term = motor_config.ki * motor_state.integral;
// 微分项
float d_term = motor_config.kd * (error - motor_state.last_error) / dt;
motor_state.last_error = error;
// 输出
float output = p_term + i_term + d_term;
// 限幅
if (output > 100) output = 100;
if (output < 0) output = 0;
return output;
}
/**
* 设置电机转速
*/
void motor_set_speed(uint16_t rpm, MotorDirection_t dir)
{
// 限制最大转速
if (rpm > motor_config.max_rpm) {
rpm = motor_config.max_rpm;
}
motor_state.target_rpm = rpm;
motor_state.direction = dir;
// 设置方向
if (dir == MOTOR_DIR_CW) {
HAL_GPIO_WritePin(motor_config.dir_port, motor_config.dir_pin, GPIO_PIN_SET);
} else if (dir == MOTOR_DIR_CCW) {
HAL_GPIO_WritePin(motor_config.dir_port, motor_config.dir_pin, GPIO_PIN_RESET);
}
// 启动或停止
if (rpm > 0 && dir != MOTOR_DIR_STOP) {
HAL_GPIO_WritePin(motor_config.en_port, motor_config.en_pin, GPIO_PIN_SET);
motor_state.start_time = HAL_GetTick();
} else {
HAL_GPIO_WritePin(motor_config.en_port, motor_config.en_pin, GPIO_PIN_RESET);
motor_state.target_rpm = 0;
}
}
/**
* 电机控制循环 (在定时器中断中调用)
*/
void motor_control_loop(void)
{
static uint32_t last_time = 0;
uint32_t now = HAL_GetTick();
float dt = (now - last_time) / 1000.0f;
last_time = now;
if (dt <= 0 || dt > 0.1f) return;
// 读取实际转速
motor_read_rpm();
// 加速度限制 (软启动)
static uint16_t ramped_target = 0;
float max_delta = motor_config.max_accel * dt;
if (motor_state.target_rpm > ramped_target) {
ramped_target += (uint16_t)max_delta;
if (ramped_target > motor_state.target_rpm) {
ramped_target = motor_state.target_rpm;
}
} else if (motor_state.target_rpm < ramped_target) {
if (ramped_target > max_delta) {
ramped_target -= (uint16_t)max_delta;
} else {
ramped_target = 0;
}
}
// PID计算
motor_state.duty_cycle = motor_pid_control(ramped_target, motor_state.actual_rpm, dt);
// 设置PWM
uint32_t pulse = (uint32_t)(motor_state.duty_cycle * motor_config.htim->Init.Period / 100);
__HAL_TIM_SET_COMPARE(motor_config.htim, motor_config.channel, pulse);
// 更新运行时间
if (motor_state.actual_rpm > 0) {
motor_state.run_time_ms = now - motor_state.start_time;
}
// 堵转检测
if (motor_state.target_rpm > 50 && motor_state.actual_rpm < 10 &&
motor_state.run_time_ms > 3000) {
motor_state.stall = 1;
motor_set_speed(0, MOTOR_DIR_STOP); // 停机保护
}
}
/**
* 洗涤动作 - 正反转摆动
*/
void motor_wash_action(uint16_t rpm, uint16_t cw_time_ms, uint16_t ccw_time_ms,
uint16_t pause_time_ms)
{
// 顺时针
motor_set_speed(rpm, MOTOR_DIR_CW);
HAL_Delay(cw_time_ms);
// 暂停
motor_set_speed(0, MOTOR_DIR_STOP);
HAL_Delay(pause_time_ms);
// 逆时针
motor_set_speed(rpm, MOTOR_DIR_CCW);
HAL_Delay(ccw_time_ms);
// 暂停
motor_set_speed(0, MOTOR_DIR_STOP);
HAL_Delay(pause_time_ms);
}
加热控制
c
/**
* 加热系统控制
*
* PTC加热器或电热管,通过继电器/可控硅控制
*/
typedef struct {
GPIO_TypeDef *relay_port;
uint16_t relay_pin;
float max_power_w; // 最大功率
float temp_threshold_high; // 过热保护温度
float temp_threshold_low; // 恢复温度
} HeaterConfig_t;
typedef struct {
uint8_t enabled;
float target_temp;
float current_temp;
float heater_temp; // 加热器本体温度
uint8_t heating; // 正在加热
uint8_t overtemp; // 过热保护
uint32_t heat_time_ms; // 本次加热时间
uint32_t total_heat_time; // 总加热时间
} HeaterState_t;
static HeaterConfig_t heater_config = {
.relay_port = GPIOC,
.relay_pin = GPIO_PIN_0,
.max_power_w = 2000,
.temp_threshold_high = 90,
.temp_threshold_low = 80
};
static HeaterState_t heater_state;
/**
* 加热开关控制
*/
void heater_set(uint8_t on)
{
if (on && !heater_state.overtemp) {
HAL_GPIO_WritePin(heater_config.relay_port, heater_config.relay_pin, GPIO_PIN_SET);
heater_state.heating = 1;
} else {
HAL_GPIO_WritePin(heater_config.relay_port, heater_config.relay_pin, GPIO_PIN_RESET);
heater_state.heating = 0;
}
}
/**
* 温度控制 - 带滞环
*/
void heater_control_loop(void)
{
// 读取温度
heater_state.current_temp = get_water_temperature();
heater_state.heater_temp = get_heater_temperature();
// 过热保护检查
if (heater_state.heater_temp > heater_config.temp_threshold_high) {
heater_state.overtemp = 1;
heater_set(0);
return;
}
// 过热恢复
if (heater_state.overtemp &&
heater_state.heater_temp < heater_config.temp_threshold_low) {
heater_state.overtemp = 0;
}
if (!heater_state.enabled) {
heater_set(0);
return;
}
// 滞环控制
float hysteresis = 2.0f; // 2度滞环
if (heater_state.current_temp < heater_state.target_temp - hysteresis) {
heater_set(1);
} else if (heater_state.current_temp > heater_state.target_temp + hysteresis) {
heater_set(0);
}
// 在滞环范围内保持当前状态
}
/**
* 设置目标温度
*/
void heater_set_target(float temp)
{
// 限制温度范围
if (temp < 20) temp = 20;
if (temp > 95) temp = 95;
heater_state.target_temp = temp;
heater_state.enabled = 1;
}
/**
* 关闭加热
*/
void heater_disable(void)
{
heater_state.enabled = 0;
heater_set(0);
}
/**
* 估算加热时间
*/
uint32_t heater_estimate_time(float current_temp, float target_temp, float water_volume_L)
{
if (current_temp >= target_temp) return 0;
float delta_temp = target_temp - current_temp;
// Q = m × c × ΔT
// t = Q / P
// 水的比热容 c = 4186 J/(kg·°C)
float energy_j = water_volume_L * 4186 * delta_temp;
float time_s = energy_j / (heater_config.max_power_w * 0.9f); // 90%效率
return (uint32_t)(time_s * 1000); // 转毫秒
}
进水阀与排水泵
c
/**
* 进水阀控制
*
* 通常有冷水阀和热水阀(部分机型)
*/
typedef enum {
INLET_VALVE_COLD,
INLET_VALVE_HOT,
INLET_VALVE_BOTH,
INLET_VALVE_NONE
} InletValve_t;
typedef struct {
GPIO_TypeDef *cold_port;
uint16_t cold_pin;
GPIO_TypeDef *hot_port;
uint16_t hot_pin;
} InletValveConfig_t;
static InletValveConfig_t inlet_config;
/**
* 控制进水阀
*/
void inlet_valve_set(InletValve_t valve)
{
switch (valve) {
case INLET_VALVE_COLD:
HAL_GPIO_WritePin(inlet_config.cold_port, inlet_config.cold_pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(inlet_config.hot_port, inlet_config.hot_pin, GPIO_PIN_RESET);
break;
case INLET_VALVE_HOT:
HAL_GPIO_WritePin(inlet_config.cold_port, inlet_config.cold_pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(inlet_config.hot_port, inlet_config.hot_pin, GPIO_PIN_SET);
break;
case INLET_VALVE_BOTH:
HAL_GPIO_WritePin(inlet_config.cold_port, inlet_config.cold_pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(inlet_config.hot_port, inlet_config.hot_pin, GPIO_PIN_SET);
break;
case INLET_VALVE_NONE:
default:
HAL_GPIO_WritePin(inlet_config.cold_port, inlet_config.cold_pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(inlet_config.hot_port, inlet_config.hot_pin, GPIO_PIN_RESET);
break;
}
}
/**
* 排水泵控制
*/
typedef struct {
GPIO_TypeDef *pump_port;
uint16_t pump_pin;
} DrainPumpConfig_t;
static DrainPumpConfig_t drain_config;
void drain_pump_set(uint8_t on)
{
HAL_GPIO_WritePin(drain_config.pump_port, drain_config.pump_pin,
on ? GPIO_PIN_SET : GPIO_PIN_RESET);
}
/**
* 进水到指定水位
*/
int fill_water_to_level(WaterLevel_t target, uint32_t timeout_ms)
{
uint32_t start = HAL_GetTick();
inlet_valve_set(INLET_VALVE_COLD);
while (!water_level_reached(target)) {
// 超时检查
if (HAL_GetTick() - start > timeout_ms) {
inlet_valve_set(INLET_VALVE_NONE);
return -1; // 进水超时
}
// 溢出检查
if (water_level_overflow()) {
inlet_valve_set(INLET_VALVE_NONE);
return -2; // 溢出
}
HAL_Delay(100);
}
inlet_valve_set(INLET_VALVE_NONE);
return 0;
}
/**
* 排水到空
*/
int drain_water(uint32_t timeout_ms)
{
uint32_t start = HAL_GetTick();
drain_pump_set(1);
while (water_level_get_mm() > 10) { // 允许少量残留
if (HAL_GetTick() - start > timeout_ms) {
drain_pump_set(0);
return -1; // 排水超时
}
HAL_Delay(100);
}
// 多排几秒确保排干
HAL_Delay(5000);
drain_pump_set(0);
return 0;
}
洗涤模式定义
模式参数结构
c
/**
* 洗涤模式参数定义
*/
// 洗涤阶段
typedef enum {
WASH_PHASE_PREWASH, // 预洗
WASH_PHASE_MAIN_WASH, // 主洗
WASH_PHASE_RINSE, // 漂洗
WASH_PHASE_SPIN, // 脱水
WASH_PHASE_DRY // 烘干(部分机型)
} WashPhase_t;
// 单个洗涤阶段参数
typedef struct {
WashPhase_t phase;
// 水位和温度
WaterLevel_t water_level;
float water_temp; // 0 = 不加热
// 电机参数
uint16_t motor_rpm;
uint16_t rotate_time_ms; // 单次旋转时间
uint16_t pause_time_ms; // 暂停时间
// 时间
uint32_t duration_ms; // 阶段持续时间
// 特殊标志
uint8_t drain_after; // 结束后排水
uint8_t add_detergent; // 是否投放洗涤剂
uint8_t gentle_mode; // 轻柔模式
} WashPhaseConfig_t;
// 完整洗涤程序
typedef struct {
char name[32];
// 阶段配置
WashPhaseConfig_t phases[10];
uint8_t num_phases;
// 脱水参数
uint16_t spin_rpm; // 脱水转速
uint32_t spin_duration_ms; // 脱水时间
// 漂洗次数
uint8_t rinse_count;
// 估计时间
uint32_t estimated_time_min;
// 适用衣物
char suitable_for[64];
// 特殊功能
uint8_t allow_pause; // 允许暂停添衣
uint8_t night_mode; // 夜间模式
uint8_t eco_mode; // 节能模式
} WashProgram_t;
标准洗涤模式
c
/**
* 标准洗涤模式定义
*/
// 标准洗模式
static const WashProgram_t PROGRAM_STANDARD = {
.name = "标准洗",
.num_phases = 5,
.phases = {
// 预洗
{
.phase = WASH_PHASE_PREWASH,
.water_level = WATER_LEVEL_MEDIUM,
.water_temp = 0, // 冷水
.motor_rpm = 45,
.rotate_time_ms = 10000,
.pause_time_ms = 3000,
.duration_ms = 5 * 60 * 1000, // 5分钟
.drain_after = 1,
.add_detergent = 0,
.gentle_mode = 0
},
// 主洗
{
.phase = WASH_PHASE_MAIN_WASH,
.water_level = WATER_LEVEL_MEDIUM,
.water_temp = 40, // 40度
.motor_rpm = 50,
.rotate_time_ms = 15000,
.pause_time_ms = 5000,
.duration_ms = 15 * 60 * 1000, // 15分钟
.drain_after = 1,
.add_detergent = 1,
.gentle_mode = 0
},
// 漂洗1
{
.phase = WASH_PHASE_RINSE,
.water_level = WATER_LEVEL_HIGH,
.water_temp = 0,
.motor_rpm = 45,
.rotate_time_ms = 10000,
.pause_time_ms = 3000,
.duration_ms = 8 * 60 * 1000,
.drain_after = 1,
.add_detergent = 0,
.gentle_mode = 0
},
// 漂洗2
{
.phase = WASH_PHASE_RINSE,
.water_level = WATER_LEVEL_HIGH,
.water_temp = 0,
.motor_rpm = 45,
.rotate_time_ms = 10000,
.pause_time_ms = 3000,
.duration_ms = 8 * 60 * 1000,
.drain_after = 1,
.add_detergent = 0,
.gentle_mode = 0
},
// 脱水
{
.phase = WASH_PHASE_SPIN,
.water_level = WATER_LEVEL_EMPTY,
.water_temp = 0,
.motor_rpm = 1000,
.rotate_time_ms = 0, // 连续旋转
.pause_time_ms = 0,
.duration_ms = 8 * 60 * 1000,
.drain_after = 0,
.add_detergent = 0,
.gentle_mode = 0
}
},
.spin_rpm = 1000,
.spin_duration_ms = 8 * 60 * 1000,
.rinse_count = 2,
.estimated_time_min = 55,
.suitable_for = "棉麻、化纤等日常衣物",
.allow_pause = 1,
.night_mode = 0,
.eco_mode = 0
};
// 加热洗模式 (高温消毒)
static const WashProgram_t PROGRAM_HOT_WASH = {
.name = "高温洗",
.num_phases = 5,
.phases = {
// 预洗 - 温水
{
.phase = WASH_PHASE_PREWASH,
.water_level = WATER_LEVEL_MEDIUM,
.water_temp = 40,
.motor_rpm = 45,
.rotate_time_ms = 10000,
.pause_time_ms = 3000,
.duration_ms = 8 * 60 * 1000,
.drain_after = 1,
.add_detergent = 0,
.gentle_mode = 0
},
// 主洗 - 高温
{
.phase = WASH_PHASE_MAIN_WASH,
.water_level = WATER_LEVEL_MEDIUM,
.water_temp = 60, // 60度高温
.motor_rpm = 50,
.rotate_time_ms = 15000,
.pause_time_ms = 5000,
.duration_ms = 25 * 60 * 1000, // 25分钟
.drain_after = 1,
.add_detergent = 1,
.gentle_mode = 0
},
// 漂洗
{
.phase = WASH_PHASE_RINSE,
.water_level = WATER_LEVEL_HIGH,
.water_temp = 0,
.motor_rpm = 45,
.rotate_time_ms = 10000,
.pause_time_ms = 3000,
.duration_ms = 10 * 60 * 1000,
.drain_after = 1,
.add_detergent = 0,
.gentle_mode = 0
},
{
.phase = WASH_PHASE_RINSE,
.water_level = WATER_LEVEL_HIGH,
.water_temp = 0,
.motor_rpm = 45,
.rotate_time_ms = 10000,
.pause_time_ms = 3000,
.duration_ms = 10 * 60 * 1000,
.drain_after = 1,
.add_detergent = 0,
.gentle_mode = 0
},
// 脱水
{
.phase = WASH_PHASE_SPIN,
.water_level = WATER_LEVEL_EMPTY,
.water_temp = 0,
.motor_rpm = 1200,
.rotate_time_ms = 0,
.pause_time_ms = 0,
.duration_ms = 10 * 60 * 1000,
.drain_after = 0,
.add_detergent = 0,
.gentle_mode = 0
}
},
.spin_rpm = 1200,
.spin_duration_ms = 10 * 60 * 1000,
.rinse_count = 2,
.estimated_time_min = 90,
.suitable_for = "床单、毛巾、内衣等需消毒衣物",
.allow_pause = 0, // 高温时不允许开门
.night_mode = 0,
.eco_mode = 0
};
// 羽绒服模式
static const WashProgram_t PROGRAM_DOWN_JACKET = {
.name = "羽绒服",
.num_phases = 6,
.phases = {
// 浸泡
{
.phase = WASH_PHASE_PREWASH,
.water_level = WATER_LEVEL_HIGH,
.water_temp = 30, // 温水浸泡
.motor_rpm = 25, // 极低转速
.rotate_time_ms = 5000,
.pause_time_ms = 30000, // 长暂停
.duration_ms = 10 * 60 * 1000,
.drain_after = 0,
.add_detergent = 1,
.gentle_mode = 1
},
// 轻柔洗涤
{
.phase = WASH_PHASE_MAIN_WASH,
.water_level = WATER_LEVEL_HIGH,
.water_temp = 30,
.motor_rpm = 30, // 低转速
.rotate_time_ms = 8000,
.pause_time_ms = 10000,
.duration_ms = 15 * 60 * 1000,
.drain_after = 1,
.add_detergent = 0,
.gentle_mode = 1
},
// 多次漂洗 - 羽绒需要充分漂洗
{
.phase = WASH_PHASE_RINSE,
.water_level = WATER_LEVEL_FULL,
.water_temp = 0,
.motor_rpm = 30,
.rotate_time_ms = 8000,
.pause_time_ms = 10000,
.duration_ms = 10 * 60 * 1000,
.drain_after = 1,
.add_detergent = 0,
.gentle_mode = 1
},
{
.phase = WASH_PHASE_RINSE,
.water_level = WATER_LEVEL_FULL,
.water_temp = 0,
.motor_rpm = 30,
.rotate_time_ms = 8000,
.pause_time_ms = 10000,
.duration_ms = 10 * 60 * 1000,
.drain_after = 1,
.add_detergent = 0,
.gentle_mode = 1
},
{
.phase = WASH_PHASE_RINSE,
.water_level = WATER_LEVEL_FULL,
.water_temp = 0,
.motor_rpm = 30,
.rotate_time_ms = 8000,
.pause_time_ms = 10000,
.duration_ms = 10 * 60 * 1000,
.drain_after = 1,
.add_detergent = 0,
.gentle_mode = 1
},
// 低速脱水 - 避免羽绒结块
{
.phase = WASH_PHASE_SPIN,
.water_level = WATER_LEVEL_EMPTY,
.water_temp = 0,
.motor_rpm = 600, // 低速脱水
.rotate_time_ms = 0,
.pause_time_ms = 0,
.duration_ms = 6 * 60 * 1000,
.drain_after = 0,
.add_detergent = 0,
.gentle_mode = 1
}
},
.spin_rpm = 600,
.spin_duration_ms = 6 * 60 * 1000,
.rinse_count = 3,
.estimated_time_min = 70,
.suitable_for = "羽绒服、羽绒被等蓬松衣物",
.allow_pause = 1,
.night_mode = 0,
.eco_mode = 0
};
// 毛绒/羊毛模式
static const WashProgram_t PROGRAM_WOOL = {
.name = "毛绒/羊毛",
.num_phases = 4,
.phases = {
// 轻柔洗涤
{
.phase = WASH_PHASE_MAIN_WASH,
.water_level = WATER_LEVEL_HIGH,
.water_temp = 30, // 低温
.motor_rpm = 25, // 极低转速
.rotate_time_ms = 5000,
.pause_time_ms = 15000, // 长暂停
.duration_ms = 12 * 60 * 1000,
.drain_after = 1,
.add_detergent = 1,
.gentle_mode = 1
},
// 漂洗
{
.phase = WASH_PHASE_RINSE,
.water_level = WATER_LEVEL_HIGH,
.water_temp = 0,
.motor_rpm = 25,
.rotate_time_ms = 5000,
.pause_time_ms = 15000,
.duration_ms = 8 * 60 * 1000,
.drain_after = 1,
.add_detergent = 0,
.gentle_mode = 1
},
{
.phase = WASH_PHASE_RINSE,
.water_level = WATER_LEVEL_HIGH,
.water_temp = 0,
.motor_rpm = 25,
.rotate_time_ms = 5000,
.pause_time_ms = 15000,
.duration_ms = 8 * 60 * 1000,
.drain_after = 1,
.add_detergent = 0,
.gentle_mode = 1
},
// 极低速脱水
{
.phase = WASH_PHASE_SPIN,
.water_level = WATER_LEVEL_EMPTY,
.water_temp = 0,
.motor_rpm = 400, // 极低速脱水
.rotate_time_ms = 0,
.pause_time_ms = 0,
.duration_ms = 4 * 60 * 1000,
.drain_after = 0,
.add_detergent = 0,
.gentle_mode = 1
}
},
.spin_rpm = 400,
.spin_duration_ms = 4 * 60 * 1000,
.rinse_count = 2,
.estimated_time_min = 40,
.suitable_for = "羊毛、羊绒、丝绸等精细衣物",
.allow_pause = 1,
.night_mode = 0,
.eco_mode = 0
};
// 夜间洗模式
static const WashProgram_t PROGRAM_NIGHT = {
.name = "夜间洗",
.num_phases = 5,
.phases = {
// 静音预洗
{
.phase = WASH_PHASE_PREWASH,
.water_level = WATER_LEVEL_MEDIUM,
.water_temp = 0,
.motor_rpm = 35, // 低转速降噪
.rotate_time_ms = 8000,
.pause_time_ms = 5000,
.duration_ms = 5 * 60 * 1000,
.drain_after = 1,
.add_detergent = 0,
.gentle_mode = 1
},
// 静音主洗
{
.phase = WASH_PHASE_MAIN_WASH,
.water_level = WATER_LEVEL_MEDIUM,
.water_temp = 30,
.motor_rpm = 40, // 降低转速
.rotate_time_ms = 12000,
.pause_time_ms = 5000,
.duration_ms = 20 * 60 * 1000, // 延长时间补偿
.drain_after = 1,
.add_detergent = 1,
.gentle_mode = 0
},
// 漂洗
{
.phase = WASH_PHASE_RINSE,
.water_level = WATER_LEVEL_HIGH,
.water_temp = 0,
.motor_rpm = 35,
.rotate_time_ms = 10000,
.pause_time_ms = 5000,
.duration_ms = 10 * 60 * 1000,
.drain_after = 1,
.add_detergent = 0,
.gentle_mode = 0
},
{
.phase = WASH_PHASE_RINSE,
.water_level = WATER_LEVEL_HIGH,
.water_temp = 0,
.motor_rpm = 35,
.rotate_time_ms = 10000,
.pause_time_ms = 5000,
.duration_ms = 10 * 60 * 1000,
.drain_after = 1,
.add_detergent = 0,
.gentle_mode = 0
},
// 静音脱水
{
.phase = WASH_PHASE_SPIN,
.water_level = WATER_LEVEL_EMPTY,
.water_temp = 0,
.motor_rpm = 800, // 降低脱水转速
.rotate_time_ms = 0,
.pause_time_ms = 0,
.duration_ms = 10 * 60 * 1000, // 延长时间
.drain_after = 0,
.add_detergent = 0,
.gentle_mode = 0
}
},
.spin_rpm = 800,
.spin_duration_ms = 10 * 60 * 1000,
.rinse_count = 2,
.estimated_time_min = 70,
.suitable_for = "夜间洗涤,降低噪音",
.allow_pause = 1,
.night_mode = 1,
.eco_mode = 0
};
// 节能模式
static const WashProgram_t PROGRAM_ECO = {
.name = "节能洗",
.num_phases = 4,
.phases = {
// 主洗 - 低水位、低温、延长时间
{
.phase = WASH_PHASE_MAIN_WASH,
.water_level = WATER_LEVEL_LOW,
.water_temp = 20, // 低温或不加热
.motor_rpm = 45,
.rotate_time_ms = 20000, // 延长摔打时间
.pause_time_ms = 8000,
.duration_ms = 25 * 60 * 1000,
.drain_after = 1,
.add_detergent = 1,
.gentle_mode = 0
},
// 单次漂洗
{
.phase = WASH_PHASE_RINSE,
.water_level = WATER_LEVEL_MEDIUM,
.water_temp = 0,
.motor_rpm = 45,
.rotate_time_ms = 15000,
.pause_time_ms = 5000,
.duration_ms = 12 * 60 * 1000,
.drain_after = 1,
.add_detergent = 0,
.gentle_mode = 0
},
// 喷淋漂洗(省水)
{
.phase = WASH_PHASE_RINSE,
.water_level = WATER_LEVEL_LOW, // 低水位+喷淋
.water_temp = 0,
.motor_rpm = 100, // 边转边喷淋
.rotate_time_ms = 30000,
.pause_time_ms = 0,
.duration_ms = 5 * 60 * 1000,
.drain_after = 1,
.add_detergent = 0,
.gentle_mode = 0
},
// 脱水
{
.phase = WASH_PHASE_SPIN,
.water_level = WATER_LEVEL_EMPTY,
.water_temp = 0,
.motor_rpm = 1000,
.rotate_time_ms = 0,
.pause_time_ms = 0,
.duration_ms = 8 * 60 * 1000,
.drain_after = 0,
.add_detergent = 0,
.gentle_mode = 0
}
},
.spin_rpm = 1000,
.spin_duration_ms = 8 * 60 * 1000,
.rinse_count = 2,
.estimated_time_min = 60,
.suitable_for = "轻度脏污衣物,省水省电",
.allow_pause = 1,
.night_mode = 0,
.eco_mode = 1
};
// 快洗模式
static const WashProgram_t PROGRAM_QUICK = {
.name = "快洗15分钟",
.num_phases = 3,
.phases = {
// 快速洗涤
{
.phase = WASH_PHASE_MAIN_WASH,
.water_level = WATER_LEVEL_LOW,
.water_temp = 0,
.motor_rpm = 55,
.rotate_time_ms = 10000,
.pause_time_ms = 2000,
.duration_ms = 6 * 60 * 1000,
.drain_after = 1,
.add_detergent = 1,
.gentle_mode = 0
},
// 单次漂洗
{
.phase = WASH_PHASE_RINSE,
.water_level = WATER_LEVEL_MEDIUM,
.water_temp = 0,
.motor_rpm = 50,
.rotate_time_ms = 8000,
.pause_time_ms = 2000,
.duration_ms = 5 * 60 * 1000,
.drain_after = 1,
.add_detergent = 0,
.gentle_mode = 0
},
// 快速脱水
{
.phase = WASH_PHASE_SPIN,
.water_level = WATER_LEVEL_EMPTY,
.water_temp = 0,
.motor_rpm = 1200,
.rotate_time_ms = 0,
.pause_time_ms = 0,
.duration_ms = 4 * 60 * 1000,
.drain_after = 0,
.add_detergent = 0,
.gentle_mode = 0
}
},
.spin_rpm = 1200,
.spin_duration_ms = 4 * 60 * 1000,
.rinse_count = 1,
.estimated_time_min = 15,
.suitable_for = "少量轻度脏污衣物",
.allow_pause = 1,
.night_mode = 0,
.eco_mode = 0
};
模式参数对比
c
/**
* 各模式参数对比表
*/
/*
┌────────────────────────────────────────────────────────────────────────────────────────┐
│ 洗涤模式参数对比 │
├──────────────┬────────┬────────┬────────┬────────┬────────┬────────────────────────────┤
│ 模式 │ 水温 │ 水位 │ 洗涤转速│ 脱水转速│ 时间 │ 特点 │
├──────────────┼────────┼────────┼────────┼────────┼────────┼────────────────────────────┤
│ 标准洗 │ 40°C │ 中 │ 50rpm │ 1000rpm│ 55min │ 日常衣物通用 │
├──────────────┼────────┼────────┼────────┼────────┼────────┼────────────────────────────┤
│ 高温洗 │ 60°C │ 中 │ 50rpm │ 1200rpm│ 90min │ 杀菌消毒,床品内衣 │
├──────────────┼────────┼────────┼────────┼────────┼────────┼────────────────────────────┤
│ 羽绒服 │ 30°C │ 高 │ 30rpm │ 600rpm │ 70min │ 低转速防结块,多次漂洗 │
├──────────────┼────────┼────────┼────────┼────────┼────────┼────────────────────────────┤
│ 毛绒/羊毛 │ 30°C │ 高 │ 25rpm │ 400rpm │ 40min │ 极低转速,保护纤维 │
├──────────────┼────────┼────────┼────────┼────────┼────────┼────────────────────────────┤
│ 夜间洗 │ 30°C │ 中 │ 40rpm │ 800rpm │ 70min │ 低噪音,延长时间补偿 │
├──────────────┼────────┼────────┼────────┼────────┼────────┼────────────────────────────┤
│ 节能洗 │ 20°C │ 低 │ 45rpm │ 1000rpm│ 60min │ 省水省电,延长摔打 │
├──────────────┼────────┼────────┼────────┼────────┼────────┼────────────────────────────┤
│ 快洗15分钟 │ 冷水 │ 低 │ 55rpm │ 1200rpm│ 15min │ 少量轻污,单次漂洗 │
├──────────────┼────────┼────────┼────────┼────────┼────────┼────────────────────────────┤
│ 童装 │ 40°C │ 高 │ 40rpm │ 800rpm │ 60min │ 多次漂洗,去除洗涤剂残留 │
├──────────────┼────────┼────────┼────────┼────────┼────────┼────────────────────────────┤
│ 运动服 │ 30°C │ 中 │ 45rpm │ 1000rpm│ 45min │ 去除汗味,保护弹性 │
├──────────────┼────────┼────────┼────────┼────────┼────────┼────────────────────────────┤
│ 大件床品 │ 40°C │ 满 │ 35rpm │ 800rpm │ 80min │ 满水位,低转速防缠绕 │
└──────────────┴────────┴────────┴────────┴────────┴────────┴────────────────────────────┘
转速与效果关系:
- 洗涤转速越高,摔打力越大,去污效果越好,但对衣物磨损也越大
- 脱水转速越高,脱水效果越好,但噪音越大,对精细衣物可能造成损伤
温度与效果关系:
- 温度越高,洗涤剂活性越强,去污效果越好
- 但高温会使某些衣物缩水变形
- 60°C以上可有效杀灭大部分细菌
水位与效果关系:
- 水位越高,衣物浸泡越充分,但用水量大
- 低水位靠摔打洗涤,省水但需延长时间
*/
洗涤状态机
c
/**
* 洗涤状态机
*/
typedef enum {
STATE_IDLE, // 空闲
STATE_PREPARING, // 准备(检查门锁等)
STATE_FILLING, // 进水
STATE_HEATING, // 加热
STATE_WASHING, // 洗涤
STATE_DRAINING, // 排水
STATE_SPINNING, // 脱水
STATE_RINSING, // 漂洗
STATE_PAUSED, // 暂停
STATE_ADDING_CLOTHES, // 添衣中
STATE_FINISHED, // 完成
STATE_ERROR // 故障
} WashState_t;
typedef struct {
WashState_t state;
const WashProgram_t *program; // 当前程序
uint8_t current_phase; // 当前阶段索引
// 时间管理
uint32_t phase_start_time;
uint32_t total_elapsed_time;
uint32_t remaining_time;
// 运行参数
float current_temp;
uint16_t current_water_level;
uint16_t current_motor_rpm;
// 中途添衣
uint8_t add_clothes_requested;
uint8_t add_clothes_allowed;
// 错误信息
uint8_t error_code;
char error_message[64];
} WashContext_t;
static WashContext_t wash_ctx;
/**
* 状态机主循环
*/
void wash_state_machine_run(void)
{
switch (wash_ctx.state) {
case STATE_IDLE:
// 等待用户启动
break;
case STATE_PREPARING:
handle_preparing();
break;
case STATE_FILLING:
handle_filling();
break;
case STATE_HEATING:
handle_heating();
break;
case STATE_WASHING:
handle_washing();
break;
case STATE_DRAINING:
handle_draining();
break;
case STATE_SPINNING:
handle_spinning();
break;
case STATE_RINSING:
handle_rinsing();
break;
case STATE_PAUSED:
handle_paused();
break;
case STATE_ADDING_CLOTHES:
handle_adding_clothes();
break;
case STATE_FINISHED:
handle_finished();
break;
case STATE_ERROR:
handle_error();
break;
}
// 更新剩余时间
update_remaining_time();
// 安全检查
safety_check();
}
/**
* 准备阶段
*/
void handle_preparing(void)
{
// 检查门锁状态
DoorState_t door = door_get_state();
if (door == DOOR_STATE_OPEN) {
// 等待关门
return;
}
// 尝试锁门
if (door != DOOR_STATE_LOCKED) {
if (door_lock() != 0) {
set_error(ERROR_DOOR_LOCK_FAIL, "门锁失败");
return;
}
}
// 检查衣物重量
float weight = weight_read_kg();
if (weight > 10.0f) { // 超过10kg
set_error(ERROR_OVERLOAD, "衣物过重");
return;
}
// 进入进水阶段
wash_ctx.state = STATE_FILLING;
wash_ctx.phase_start_time = HAL_GetTick();
}
/**
* 进水阶段
*/
void handle_filling(void)
{
WashPhaseConfig_t *phase = &wash_ctx.program->phases[wash_ctx.current_phase];
// 检查是否达到目标水位
if (water_level_reached(phase->water_level)) {
inlet_valve_set(INLET_VALVE_NONE);
// 需要加热?
if (phase->water_temp > 0 &&
get_water_temperature() < phase->water_temp - 5) {
wash_ctx.state = STATE_HEATING;
} else {
wash_ctx.state = STATE_WASHING;
}
wash_ctx.phase_start_time = HAL_GetTick();
return;
}
// 继续进水
inlet_valve_set(INLET_VALVE_COLD);
// 溢出保护
if (water_level_overflow()) {
inlet_valve_set(INLET_VALVE_NONE);
set_error(ERROR_OVERFLOW, "水位溢出");
}
// 超时保护 (5分钟)
if (HAL_GetTick() - wash_ctx.phase_start_time > 5 * 60 * 1000) {
inlet_valve_set(INLET_VALVE_NONE);
set_error(ERROR_FILL_TIMEOUT, "进水超时");
}
}
/**
* 加热阶段
*/
void handle_heating(void)
{
WashPhaseConfig_t *phase = &wash_ctx.program->phases[wash_ctx.current_phase];
float current_temp = get_water_temperature();
wash_ctx.current_temp = current_temp;
// 达到目标温度
if (current_temp >= phase->water_temp - 2) {
heater_disable();
wash_ctx.state = STATE_WASHING;
wash_ctx.phase_start_time = HAL_GetTick();
return;
}
// 继续加热
heater_set_target(phase->water_temp);
heater_control_loop();
// 同时低速搅动,均匀加热
static uint32_t last_rotate = 0;
if (HAL_GetTick() - last_rotate > 30000) { // 每30秒
motor_wash_action(30, 5000, 5000, 2000);
last_rotate = HAL_GetTick();
}
// 超时保护 (30分钟)
if (HAL_GetTick() - wash_ctx.phase_start_time > 30 * 60 * 1000) {
heater_disable();
set_error(ERROR_HEAT_TIMEOUT, "加热超时");
}
}
/**
* 洗涤阶段
*/
void handle_washing(void)
{
WashPhaseConfig_t *phase = &wash_ctx.program->phases[wash_ctx.current_phase];
// 检查是否完成当前阶段
if (HAL_GetTick() - wash_ctx.phase_start_time >= phase->duration_ms) {
motor_set_speed(0, MOTOR_DIR_STOP);
// 排水
if (phase->drain_after) {
wash_ctx.state = STATE_DRAINING;
} else {
advance_to_next_phase();
}
wash_ctx.phase_start_time = HAL_GetTick();
return;
}
// 执行洗涤动作
motor_wash_action(
phase->motor_rpm,
phase->rotate_time_ms,
phase->rotate_time_ms,
phase->pause_time_ms
);
// 维持水温
if (phase->water_temp > 0) {
heater_set_target(phase->water_temp);
heater_control_loop();
}
}
/**
* 排水阶段
*/
void handle_draining(void)
{
// 检查是否排干
if (water_level_get_mm() < 20) {
drain_pump_set(0);
// 进入下一阶段
advance_to_next_phase();
wash_ctx.phase_start_time = HAL_GetTick();
return;
}
// 继续排水
drain_pump_set(1);
// 超时保护 (3分钟)
if (HAL_GetTick() - wash_ctx.phase_start_time > 3 * 60 * 1000) {
drain_pump_set(0);
set_error(ERROR_DRAIN_TIMEOUT, "排水超时");
}
}
/**
* 脱水阶段
*/
void handle_spinning(void)
{
WashPhaseConfig_t *phase = &wash_ctx.program->phases[wash_ctx.current_phase];
// 检查是否完成
if (HAL_GetTick() - wash_ctx.phase_start_time >= phase->duration_ms) {
motor_set_speed(0, MOTOR_DIR_STOP);
advance_to_next_phase();
return;
}
// 平衡检测
if (check_unbalance()) {
// 尝试重新平衡
motor_set_speed(0, MOTOR_DIR_STOP);
HAL_Delay(3000);
// 低速重新分布衣物
motor_wash_action(50, 5000, 5000, 2000);
motor_wash_action(50, 5000, 5000, 2000);
}
// 逐步提升转速
static uint16_t current_rpm = 0;
if (current_rpm < phase->motor_rpm) {
current_rpm += 50; // 每次增加50rpm
if (current_rpm > phase->motor_rpm) {
current_rpm = phase->motor_rpm;
}
}
motor_set_speed(current_rpm, MOTOR_DIR_CW);
// 持续排水
drain_pump_set(1);
}
/**
* 中途添衣处理
*/
void handle_adding_clothes(void)
{
static uint32_t add_start_time = 0;
// 首次进入
if (add_start_time == 0) {
add_start_time = HAL_GetTick();
// 停止电机
motor_set_speed(0, MOTOR_DIR_STOP);
// 等待电机完全停止
HAL_Delay(3000);
// 检查水温
if (get_water_temperature() > 50) {
// 温度过高,不能开门
wash_ctx.add_clothes_allowed = 0;
wash_ctx.state = wash_ctx.state; // 返回之前状态
add_start_time = 0;
return;
}
// 解锁门
if (door_unlock(get_water_temperature(), 0) != 0) {
wash_ctx.add_clothes_allowed = 0;
wash_ctx.state = STATE_WASHING; // 返回洗涤
add_start_time = 0;
return;
}
wash_ctx.add_clothes_allowed = 1;
}
// 等待用户操作
DoorState_t door = door_get_state();
// 超时检查 (2分钟)
if (HAL_GetTick() - add_start_time > 2 * 60 * 1000) {
// 超时,关门继续
if (door == DOOR_STATE_CLOSED) {
door_lock();
wash_ctx.state = STATE_WASHING;
add_start_time = 0;
}
return;
}
// 用户关门后继续
if (door == DOOR_STATE_CLOSED &&
HAL_GetTick() - add_start_time > 5000) { // 至少等5秒
door_lock();
wash_ctx.state = STATE_WASHING;
wash_ctx.phase_start_time = HAL_GetTick(); // 重置阶段时间
add_start_time = 0;
}
}
/**
* 进入下一阶段
*/
void advance_to_next_phase(void)
{
wash_ctx.current_phase++;
if (wash_ctx.current_phase >= wash_ctx.program->num_phases) {
// 所有阶段完成
wash_ctx.state = STATE_FINISHED;
return;
}
WashPhaseConfig_t *next_phase = &wash_ctx.program->phases[wash_ctx.current_phase];
// 根据阶段类型设置状态
switch (next_phase->phase) {
case WASH_PHASE_PREWASH:
case WASH_PHASE_MAIN_WASH:
case WASH_PHASE_RINSE:
wash_ctx.state = STATE_FILLING;
break;
case WASH_PHASE_SPIN:
wash_ctx.state = STATE_SPINNING;
break;
default:
wash_ctx.state = STATE_FILLING;
break;
}
}
/**
* 完成处理
*/
void handle_finished(void)
{
// 停止所有执行器
motor_set_speed(0, MOTOR_DIR_STOP);
heater_disable();
inlet_valve_set(INLET_VALVE_NONE);
drain_pump_set(0);
// 解锁门
door_unlock(get_water_temperature(), 0);
// 蜂鸣提示
buzzer_beep(3, 500, 300); // 响3声
// 可以发送WiFi通知
// wifi_notify_complete();
}
/**
* 暂停功能
*/
void wash_pause(void)
{
if (wash_ctx.state == STATE_SPINNING ||
wash_ctx.state == STATE_ERROR) {
return; // 脱水和错误状态不能暂停
}
// 记录当前状态
static WashState_t paused_from_state;
paused_from_state = wash_ctx.state;
// 停止执行器
motor_set_speed(0, MOTOR_DIR_STOP);
heater_disable();
inlet_valve_set(INLET_VALVE_NONE);
wash_ctx.state = STATE_PAUSED;
}
/**
* 恢复功能
*/
void wash_resume(void)
{
if (wash_ctx.state != STATE_PAUSED) {
return;
}
// 检查门锁
if (door_get_state() != DOOR_STATE_LOCKED) {
if (door_lock() != 0) {
return; // 锁门失败,不能恢复
}
}
// 恢复到之前状态
wash_ctx.state = STATE_WASHING; // 简化处理
}
/**
* 请求中途添衣
*/
void wash_request_add_clothes(void)
{
// 只有在允许暂停的模式和阶段才能添衣
if (!wash_ctx.program->allow_pause) {
return;
}
// 脱水阶段不能添衣
if (wash_ctx.state == STATE_SPINNING) {
return;
}
// 水温检查
if (get_water_temperature() > 50) {
return;
}
wash_ctx.add_clothes_requested = 1;
wash_ctx.state = STATE_ADDING_CLOTHES;
}
安全保护系统
c
/**
* 安全保护系统
*/
typedef enum {
ERROR_NONE = 0,
ERROR_DOOR_LOCK_FAIL, // 门锁故障
ERROR_DOOR_OPEN, // 门未关
ERROR_OVERLOAD, // 超载
ERROR_OVERFLOW, // 溢水
ERROR_FILL_TIMEOUT, // 进水超时
ERROR_DRAIN_TIMEOUT, // 排水超时
ERROR_HEAT_TIMEOUT, // 加热超时
ERROR_MOTOR_STALL, // 电机堵转
ERROR_MOTOR_OVERCURRENT, // 电机过流
ERROR_HEATER_OVERTEMP, // 加热器过热
ERROR_WATER_TEMP_HIGH, // 水温过高
ERROR_VIBRATION, // 异常振动
ERROR_UNBALANCE, // 不平衡
ERROR_SENSOR_FAULT, // 传感器故障
ERROR_COMM_FAULT // 通信故障
} ErrorCode_t;
typedef struct {
ErrorCode_t code;
char message[64];
uint32_t timestamp;
uint8_t recoverable; // 是否可恢复
} ErrorLog_t;
#define MAX_ERROR_LOGS 20
static ErrorLog_t error_logs[MAX_ERROR_LOGS];
static uint8_t error_log_count = 0;
/**
* 设置错误
*/
void set_error(ErrorCode_t code, const char *message)
{
wash_ctx.error_code = code;
strncpy(wash_ctx.error_message, message, sizeof(wash_ctx.error_message) - 1);
wash_ctx.state = STATE_ERROR;
// 记录错误日志
if (error_log_count < MAX_ERROR_LOGS) {
error_logs[error_log_count].code = code;
strncpy(error_logs[error_log_count].message, message, 63);
error_logs[error_log_count].timestamp = HAL_GetTick();
error_logs[error_log_count].recoverable = is_error_recoverable(code);
error_log_count++;
}
// 紧急停机
emergency_stop();
}
/**
* 紧急停机
*/
void emergency_stop(void)
{
motor_set_speed(0, MOTOR_DIR_STOP);
heater_disable();
inlet_valve_set(INLET_VALVE_NONE);
drain_pump_set(0);
}
/**
* 安全检查 (周期调用)
*/
void safety_check(void)
{
// 1. 门锁状态检查
if (wash_ctx.state != STATE_IDLE &&
wash_ctx.state != STATE_FINISHED &&
wash_ctx.state != STATE_ERROR &&
wash_ctx.state != STATE_ADDING_CLOTHES) {
DoorState_t door = door_get_state();
if (door != DOOR_STATE_LOCKED) {
set_error(ERROR_DOOR_OPEN, "门已打开");
return;
}
}
// 2. 水位溢出检查
if (water_level_overflow()) {
inlet_valve_set(INLET_VALVE_NONE);
drain_pump_set(1); // 紧急排水
set_error(ERROR_OVERFLOW, "水位溢出");
return;
}
// 3. 水温检查
float water_temp = get_water_temperature();
if (water_temp > 95) {
heater_disable();
set_error(ERROR_WATER_TEMP_HIGH, "水温过高");
return;
}
// 4. 加热器温度检查
float heater_temp = get_heater_temperature();
if (heater_temp > 150) {
heater_disable();
set_error(ERROR_HEATER_OVERTEMP, "加热器过热");
return;
}
// 5. 电机堵转检查
if (motor_state.stall) {
set_error(ERROR_MOTOR_STALL, "电机堵转");
return;
}
// 6. 振动检查 (脱水时)
if (wash_ctx.state == STATE_SPINNING) {
if (check_excessive_vibration()) {
motor_set_speed(0, MOTOR_DIR_STOP);
set_error(ERROR_VIBRATION, "异常振动");
return;
}
}
// 7. 传感器自检
if (!check_sensors_ok()) {
set_error(ERROR_SENSOR_FAULT, "传感器故障");
return;
}
}
/**
* 不平衡检测
*/
int check_unbalance(void)
{
// 通过振动传感器或电机电流波动检测
// 简化实现:检测电机电流波动
static float current_samples[10];
static int sample_idx = 0;
float motor_current = read_motor_current();
current_samples[sample_idx] = motor_current;
sample_idx = (sample_idx + 1) % 10;
// 计算电流标准差
float mean = 0;
for (int i = 0; i < 10; i++) {
mean += current_samples[i];
}
mean /= 10;
float variance = 0;
for (int i = 0; i < 10; i++) {
variance += (current_samples[i] - mean) * (current_samples[i] - mean);
}
variance /= 10;
float std_dev = sqrtf(variance);
// 波动超过阈值认为不平衡
return (std_dev > mean * 0.2f); // 波动超过20%
}
/**
* 异常振动检测
*/
int check_excessive_vibration(void)
{
// 读取加速度传感器(如果有)
// 或通过电机电流分析
// 简化:返回0表示正常
return 0;
}
用户界面与显示
c
/**
* 用户界面控制
*/
typedef struct {
// 显示内容
char mode_name[32];
uint32_t remaining_time_min;
uint8_t current_phase;
float water_temp;
uint16_t spin_rpm;
// 状态指示
uint8_t washing;
uint8_t heating;
uint8_t spinning;
uint8_t door_locked;
uint8_t error;
// 选项
uint8_t selected_mode;
uint8_t temp_option; // 温度选项 0=冷水, 1=30°, 2=40°, 3=60°
uint8_t spin_option; // 脱水选项 0=不脱水, 1=低速, 2=中速, 3=高速
uint8_t rinse_option; // 漂洗次数
} UIState_t;
static UIState_t ui_state;
// 可选模式列表
static const WashProgram_t *available_programs[] = {
&PROGRAM_STANDARD,
&PROGRAM_HOT_WASH,
&PROGRAM_DOWN_JACKET,
&PROGRAM_WOOL,
&PROGRAM_NIGHT,
&PROGRAM_ECO,
&PROGRAM_QUICK
};
#define NUM_PROGRAMS (sizeof(available_programs) / sizeof(available_programs[0]))
/**
* 更新显示
*/
void ui_update_display(void)
{
// 更新状态
ui_state.remaining_time_min = wash_ctx.remaining_time / 60000;
ui_state.water_temp = wash_ctx.current_temp;
ui_state.current_phase = wash_ctx.current_phase;
ui_state.door_locked = (door_get_state() == DOOR_STATE_LOCKED);
ui_state.error = (wash_ctx.state == STATE_ERROR);
ui_state.washing = (wash_ctx.state == STATE_WASHING);
ui_state.heating = heater_state.heating;
ui_state.spinning = (wash_ctx.state == STATE_SPINNING);
// 发送到显示模块
// display_show_mode(ui_state.mode_name);
// display_show_time(ui_state.remaining_time_min);
// display_show_temp(ui_state.water_temp);
// display_show_status_icons(...);
}
/**
* 按键处理
*/
void ui_handle_key(uint8_t key)
{
switch (key) {
case KEY_MODE:
// 切换模式
if (wash_ctx.state == STATE_IDLE) {
ui_state.selected_mode = (ui_state.selected_mode + 1) % NUM_PROGRAMS;
strncpy(ui_state.mode_name,
available_programs[ui_state.selected_mode]->name, 31);
}
break;
case KEY_START:
// 启动/暂停
if (wash_ctx.state == STATE_IDLE) {
wash_start(available_programs[ui_state.selected_mode]);
} else if (wash_ctx.state == STATE_PAUSED) {
wash_resume();
} else {
wash_pause();
}
break;
case KEY_TEMP:
// 温度选项
if (wash_ctx.state == STATE_IDLE) {
ui_state.temp_option = (ui_state.temp_option + 1) % 4;
}
break;
case KEY_SPIN:
// 脱水选项
if (wash_ctx.state == STATE_IDLE) {
ui_state.spin_option = (ui_state.spin_option + 1) % 4;
}
break;
case KEY_ADD_CLOTHES:
// 添衣按钮
wash_request_add_clothes();
break;
case KEY_POWER:
// 电源键 - 长按关机
// ...
break;
}
}
/**
* 启动洗涤
*/
void wash_start(const WashProgram_t *program)
{
// 复制程序(允许用户修改参数)
wash_ctx.program = program;
wash_ctx.current_phase = 0;
wash_ctx.state = STATE_PREPARING;
wash_ctx.total_elapsed_time = 0;
wash_ctx.remaining_time = program->estimated_time_min * 60 * 1000;
wash_ctx.error_code = ERROR_NONE;
strncpy(ui_state.mode_name, program->name, 31);
}
WiFi远程控制
c
/**
* WiFi远程控制模块
*/
#include "esp_wifi.h"
#include "mqtt_client.h"
typedef struct {
uint8_t connected;
char device_id[32];
char mqtt_topic[64];
} WiFiState_t;
static WiFiState_t wifi_state;
/**
* 上报状态到云端
*/
void wifi_report_status(void)
{
if (!wifi_state.connected) return;
// 构建JSON状态
char json[512];
snprintf(json, sizeof(json),
"{"
"\"state\":\"%d\","
"\"mode\":\"%s\","
"\"phase\":%d,"
"\"remaining_time\":%lu,"
"\"water_temp\":%.1f,"
"\"door_locked\":%d,"
"\"error\":%d,"
"\"error_msg\":\"%s\""
"}",
wash_ctx.state,
wash_ctx.program ? wash_ctx.program->name : "无",
wash_ctx.current_phase,
wash_ctx.remaining_time / 60000,
wash_ctx.current_temp,
(door_get_state() == DOOR_STATE_LOCKED) ? 1 : 0,
wash_ctx.error_code,
wash_ctx.error_message
);
mqtt_publish(wifi_state.mqtt_topic, json);
}
/**
* 处理远程命令
*/
void wifi_handle_command(const char *cmd, const char *params)
{
if (strcmp(cmd, "start") == 0) {
// 远程启动
int mode_idx = atoi(params);
if (mode_idx >= 0 && mode_idx < NUM_PROGRAMS) {
wash_start(available_programs[mode_idx]);
}
}
else if (strcmp(cmd, "pause") == 0) {
wash_pause();
}
else if (strcmp(cmd, "resume") == 0) {
wash_resume();
}
else if (strcmp(cmd, "stop") == 0) {
// 强制停止
wash_ctx.state = STATE_IDLE;
emergency_stop();
door_unlock(get_water_temperature(), 0);
}
else if (strcmp(cmd, "query") == 0) {
wifi_report_status();
}
}
/**
* 完成通知
*/
void wifi_notify_complete(void)
{
if (!wifi_state.connected) return;
char json[128];
snprintf(json, sizeof(json),
"{\"event\":\"complete\",\"mode\":\"%s\",\"duration\":%lu}",
wash_ctx.program->name,
wash_ctx.total_elapsed_time / 60000
);
mqtt_publish(wifi_state.mqtt_topic, json);
}
总结
洗衣机控制系统的核心技术:
| 模块 | 关键技术 |
|---|---|
| 水位检测 | 气压式传感器、ADC滤波、水量计算 |
| 温度控制 | NTC热敏电阻、滞环控制、过热保护 |
| 称重检测 | 应变片+HX711、自动水位推荐 |
| 门锁系统 | 电磁锁、安全联锁、高温禁开 |
| 电机驱动 | BLDC变频、PID调速、软启动、堵转检测 |
| 加热控制 | 继电器/可控硅、温度维持、能耗估算 |
| 洗涤程序 | 多阶段控制、参数化配置、模式切换 |
| 安全保护 | 多重保护、错误恢复、紧急停机 |
各洗涤模式的设计原则:
| 模式 | 核心特点 |
|---|---|
| 标准洗 | 平衡去污效果和衣物保护 |
| 高温洗 | 60°C杀菌,适合床品内衣 |
| 羽绒服 | 低转速防结块,多次漂洗 |
| 毛绒 | 极低转速,保护纤维 |
| 夜间洗 | 降噪为主,延长时间补偿 |
| 节能洗 | 低水位+延长摔打,省水省电 |
| 快洗 | 短时间,适合轻污衣物 |
希望这篇文章对想了解洗衣机控制技术的朋友有帮助。代码可以作为参考框架使用,实际产品需要根据具体硬件进行调整。有问题欢迎评论区交流~
参考资料:
- 海尔/美的洗衣机维修手册
- STM32家电控制方案
- BLDC电机驱动技术
- 家电安全标准 GB4706