智能电饭锅多模式控制系统——从温度曲线到状态机完整实现

前言

去年帮朋友的小家电公司做了一款智能电饭锅的控制板开发,从最初只会把饭煮熟,到后来能做出柴火饭、煲仔饭、蒸蛋糕,中间研究了不少烹饪工艺和控制算法。

电饭锅看起来简单,实际上要把饭煮好吃,背后的温度控制逻辑相当讲究。今天把整个控制系统的设计思路分享出来,包括多模式切换、温度曲线设计、状态机实现等,希望对做类似项目的朋友有帮助。

电饭锅工作原理

基本结构

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                      智能电饭锅结构                              │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│                    ┌─────────────┐                              │
│                    │   上盖      │ ← 蒸汽阀、上盖温度传感器     │
│                    │  ┌─────┐   │                              │
│                    │  │蒸汽阀│   │                              │
│                    │  └─────┘   │                              │
│                    └─────┬─────┘                              │
│                          │                                      │
│              ┌───────────┴───────────┐                         │
│              │                       │                         │
│              │       内胆            │ ← 食物容器               │
│              │    ┌─────────┐       │                         │
│              │    │  米+水  │       │                         │
│              │    └─────────┘       │                         │
│              │                       │                         │
│              └───────────┬───────────┘                         │
│                          │                                      │
│    ┌─────────────────────┴─────────────────────┐               │
│    │              发热盘                        │               │
│    │  ┌─────┐  ┌─────────────────┐  ┌─────┐  │               │
│    │  │NTC1 │  │    加热线圈     │  │NTC2 │  │               │
│    │  │底部 │  │   (IH/电热)    │  │侧面 │  │               │
│    │  └─────┘  └─────────────────┘  └─────┘  │               │
│    └───────────────────────────────────────────┘               │
│                                                                 │
│    ┌─────────────────────────────────────────────────────────┐ │
│    │                    控制板                                │ │
│    │  ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐        │ │
│    │  │ MCU  │ │ 继电器│ │ IGBT │ │ 显示 │ │ 按键 │        │ │
│    │  └──────┘ └──────┘ └──────┘ └──────┘ └──────┘        │ │
│    └─────────────────────────────────────────────────────────┘ │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

加热方式

1. 传统电热盘

  • 电阻丝发热,传导到内胆底部
  • 功率固定,通过通断时间控制加热量
  • 成本低,但加热不均匀

2. IH电磁加热

  • 高频交流电产生交变磁场
  • 内胆自身发热(涡流效应)
  • 加热均匀,可精确控制功率
  • 成本高,效率高
c 复制代码
/**
 * 加热方式定义
 */
typedef enum {
    HEATER_TYPE_RESISTANCE,     // 电阻加热
    HEATER_TYPE_IH              // IH电磁加热
} heater_type_t;

/**
 * IH加热功率控制
 * 通过PWM占空比控制IGBT开关频率
 */
typedef struct {
    uint16_t frequency;         // 工作频率 (20-50kHz)
    uint8_t  duty_cycle;        // 占空比 (0-100%)
    uint16_t power_watt;        // 对应功率 (W)
} ih_power_config_t;

// IH功率档位表(示例)
static const ih_power_config_t ih_power_table[] = {
    {25000,  10,  100},     // 100W 保温
    {25000,  20,  200},     // 200W 小火
    {25000,  40,  400},     // 400W 中火
    {25000,  60,  600},     // 600W 中大火
    {25000,  80,  800},     // 800W 大火
    {25000, 100, 1000},     // 1000W 最大功率
};

温度传感器

c 复制代码
/**
 * NTC热敏电阻温度测量
 * 
 * NTC特性: R = R25 × exp(B × (1/T - 1/298.15))
 * 其中:
 *   R25: 25°C时的阻值(通常10kΩ或100kΩ)
 *   B: B值常数(通常3950或3435)
 *   T: 开尔文温度
 */

typedef struct {
    float r25;          // 25°C标称阻值 (Ω)
    float b_value;      // B值
    float r_series;     // 串联分压电阻 (Ω)
    float v_ref;        // 参考电压 (V)
} ntc_config_t;

/**
 * 从ADC值计算温度
 */
float ntc_calc_temperature(ntc_config_t *config, uint16_t adc_value, uint16_t adc_max)
{
    // 计算NTC电阻值
    // Vntc = Vref × ADC / ADC_MAX
    // Vntc = Vref × Rntc / (Rntc + Rs)
    // 解得: Rntc = Rs × ADC / (ADC_MAX - ADC)
    
    if (adc_value >= adc_max - 1) {
        return -40.0f;  // 开路,返回最低温度
    }
    if (adc_value <= 1) {
        return 200.0f;  // 短路,返回最高温度
    }
    
    float r_ntc = config->r_series * adc_value / (adc_max - adc_value);
    
    // 计算温度 (开尔文)
    // 1/T = 1/298.15 + ln(R/R25)/B
    float temp_k = 1.0f / (1.0f/298.15f + logf(r_ntc/config->r25) / config->b_value);
    
    // 转换为摄氏度
    return temp_k - 273.15f;
}

/**
 * 温度传感器配置
 */
typedef struct {
    ntc_config_t bottom_ntc;    // 底部温度传感器
    ntc_config_t side_ntc;      // 侧面温度传感器
    ntc_config_t lid_ntc;       // 上盖温度传感器
} temp_sensors_t;

// 典型配置
static temp_sensors_t g_temp_sensors = {
    .bottom_ntc = {.r25 = 100000, .b_value = 3950, .r_series = 10000, .v_ref = 3.3f},
    .side_ntc   = {.r25 = 100000, .b_value = 3950, .r_series = 10000, .v_ref = 3.3f},
    .lid_ntc    = {.r25 = 100000, .b_value = 3950, .r_series = 10000, .v_ref = 3.3f}
};

烹饪模式设计

模式分类

c 复制代码
/**
 * 烹饪模式定义
 */
typedef enum {
    // 基础模式
    MODE_STANDARD_RICE,         // 标准煮饭
    MODE_QUICK_RICE,            // 快速煮饭
    MODE_PORRIDGE,              // 煮粥
    
    // 米饭进阶模式
    MODE_FIREWOOD_RICE,         // 柴火饭(锅巴饭)
    MODE_CLAYPOT_RICE,          // 煲仔饭
    MODE_MIXED_RICE,            // 杂粮饭
    MODE_SUSHI_RICE,            // 寿司饭
    MODE_BROWN_RICE,            // 糙米饭
    
    // 特殊功能
    MODE_STEAM,                 // 蒸煮
    MODE_CAKE,                  // 蛋糕
    MODE_SOUP,                  // 煲汤
    MODE_YOGURT,                // 酸奶(发酵)
    MODE_SLOW_COOK,             // 慢炖
    
    // 辅助功能
    MODE_KEEP_WARM,             // 保温
    MODE_REHEAT,                // 再加热
    
    MODE_COUNT
} cooking_mode_t;

/**
 * 模式显示名称
 */
static const char* mode_names[] = {
    [MODE_STANDARD_RICE]  = "精华煮",
    [MODE_QUICK_RICE]     = "快速煮",
    [MODE_PORRIDGE]       = "煮粥",
    [MODE_FIREWOOD_RICE]  = "柴火饭",
    [MODE_CLAYPOT_RICE]   = "煲仔饭",
    [MODE_MIXED_RICE]     = "杂粮饭",
    [MODE_SUSHI_RICE]     = "寿司饭",
    [MODE_BROWN_RICE]     = "糙米饭",
    [MODE_STEAM]          = "蒸煮",
    [MODE_CAKE]           = "蛋糕",
    [MODE_SOUP]           = "煲汤",
    [MODE_YOGURT]         = "酸奶",
    [MODE_SLOW_COOK]      = "慢炖",
    [MODE_KEEP_WARM]      = "保温",
    [MODE_REHEAT]         = "再加热",
};

烹饪阶段定义

每种模式都由多个阶段组成,每个阶段有不同的温度目标和持续时间:

c 复制代码
/**
 * 烹饪阶段
 */
typedef enum {
    STAGE_IDLE,             // 空闲
    STAGE_PREHEAT,          // 预热
    STAGE_SOAK,             // 浸泡(吸水)
    STAGE_HEAT_UP,          // 升温
    STAGE_BOIL,             // 沸腾
    STAGE_SIMMER,           // 焖煮
    STAGE_CRUST,            // 结锅巴
    STAGE_BRAISE,           // 焖饭
    STAGE_COOL_DOWN,        // 降温
    STAGE_KEEP_WARM,        // 保温
    STAGE_COMPLETE          // 完成
} cooking_stage_t;

/**
 * 阶段参数
 */
typedef struct {
    cooking_stage_t stage;      // 阶段类型
    float target_temp;          // 目标温度 (°C)
    float temp_tolerance;       // 温度容差 (°C)
    uint16_t duration_sec;      // 持续时间 (秒),0表示按条件退出
    uint8_t power_level;        // 功率档位 (0-100%)
    uint8_t exit_on_temp;       // 是否达到温度就退出
    uint8_t exit_on_time;       // 是否时间到就退出
} stage_config_t;

/**
 * 完整烹饪配方
 */
typedef struct {
    cooking_mode_t mode;
    const char *name;
    uint8_t num_stages;
    stage_config_t stages[12];  // 最多12个阶段
    uint16_t total_time_min;    // 预计总时间(分钟)
} recipe_t;

各模式温度曲线详解

标准煮饭模式

这是最基础的模式,温度曲线经过精心设计:

复制代码
温度(°C)
    ↑
120 │                    ┌──────┐
    │                   ╱│沸腾  │╲
105 │                  ╱ │      │ ╲
    │                 ╱  └──────┘  ╲ 焖饭
100 │────────────────╱              ╲──────────
    │    升温      ╱                  ╲
 70 │   ┌────────╱                     ╲
    │  ╱│ 吸水  │                       ╲
 50 │ ╱ │       │                        ╲
    │╱  └───────┘                         ╲ 保温
 40 │预热                                   ────
    └─────┬──────┬─────┬──────┬─────┬──────┬───→ 时间
         5min   15min  8min   15min  10min  保温

阶段说明:
1. 预热(5min): 40→50°C,让米粒表面湿润
2. 吸水(15min): 50→70°C,米粒充分吸水膨胀
3. 升温(8min): 70→100°C,快速升温
4. 沸腾(15min): 100-105°C,大火煮透
5. 焖饭(10min): 关火焖,让水分均匀分布
6. 保温: 维持60-70°C
c 复制代码
/**
 * 标准煮饭配方
 */
static const recipe_t recipe_standard_rice = {
    .mode = MODE_STANDARD_RICE,
    .name = "精华煮",
    .num_stages = 6,
    .stages = {
        // 阶段1: 预热
        {
            .stage = STAGE_PREHEAT,
            .target_temp = 50.0f,
            .temp_tolerance = 3.0f,
            .duration_sec = 300,        // 5分钟
            .power_level = 30,
            .exit_on_temp = 1,
            .exit_on_time = 1
        },
        // 阶段2: 吸水
        {
            .stage = STAGE_SOAK,
            .target_temp = 65.0f,
            .temp_tolerance = 5.0f,
            .duration_sec = 900,        // 15分钟
            .power_level = 20,
            .exit_on_temp = 0,
            .exit_on_time = 1
        },
        // 阶段3: 升温
        {
            .stage = STAGE_HEAT_UP,
            .target_temp = 100.0f,
            .temp_tolerance = 2.0f,
            .duration_sec = 600,        // 最长10分钟
            .power_level = 100,
            .exit_on_temp = 1,
            .exit_on_time = 0
        },
        // 阶段4: 沸腾
        {
            .stage = STAGE_BOIL,
            .target_temp = 103.0f,
            .temp_tolerance = 3.0f,
            .duration_sec = 900,        // 15分钟
            .power_level = 80,
            .exit_on_temp = 0,
            .exit_on_time = 1
        },
        // 阶段5: 焖饭
        {
            .stage = STAGE_BRAISE,
            .target_temp = 95.0f,
            .temp_tolerance = 5.0f,
            .duration_sec = 600,        // 10分钟
            .power_level = 10,
            .exit_on_temp = 0,
            .exit_on_time = 1
        },
        // 阶段6: 保温
        {
            .stage = STAGE_KEEP_WARM,
            .target_temp = 65.0f,
            .temp_tolerance = 5.0f,
            .duration_sec = 0,          // 持续保温
            .power_level = 5,
            .exit_on_temp = 0,
            .exit_on_time = 0
        }
    },
    .total_time_min = 45
};

柴火饭模式

柴火饭的特点是底部有脆香的锅巴,需要在最后阶段加大火力:

复制代码
温度(°C)
    ↑
130 │                              ┌────┐
    │                             ╱│锅巴│
120 │                    ┌───────╱ │阶段│
    │                   ╱│沸腾  │  └────┘
105 │                  ╱ │      │
100 │─────────────────╱  └──────┘
    │               ╱
 70 │   ┌─────────╱
    │  ╱│  吸水  │
 50 │ ╱ └────────┘
    │╱
    └──────┬───────┬─────┬──────┬─────┬────→ 时间
          5min   12min  8min   12min  8min

特殊处理:
- 吸水时间略短(米芯保留些硬度)
- 沸腾后增加"锅巴阶段"
- 锅巴阶段底部温度达到120-130°C
- 全程火力更大
c 复制代码
/**
 * 柴火饭配方
 */
static const recipe_t recipe_firewood_rice = {
    .mode = MODE_FIREWOOD_RICE,
    .name = "柴火饭",
    .num_stages = 7,
    .stages = {
        // 预热
        {
            .stage = STAGE_PREHEAT,
            .target_temp = 55.0f,
            .temp_tolerance = 3.0f,
            .duration_sec = 300,
            .power_level = 40,
            .exit_on_temp = 1,
            .exit_on_time = 1
        },
        // 吸水(时间较短)
        {
            .stage = STAGE_SOAK,
            .target_temp = 68.0f,
            .temp_tolerance = 5.0f,
            .duration_sec = 720,        // 12分钟
            .power_level = 25,
            .exit_on_temp = 0,
            .exit_on_time = 1
        },
        // 快速升温
        {
            .stage = STAGE_HEAT_UP,
            .target_temp = 100.0f,
            .temp_tolerance = 2.0f,
            .duration_sec = 480,
            .power_level = 100,
            .exit_on_temp = 1,
            .exit_on_time = 0
        },
        // 大火沸腾
        {
            .stage = STAGE_BOIL,
            .target_temp = 105.0f,
            .temp_tolerance = 3.0f,
            .duration_sec = 720,        // 12分钟
            .power_level = 90,
            .exit_on_temp = 0,
            .exit_on_time = 1
        },
        // ★ 锅巴阶段(关键)
        {
            .stage = STAGE_CRUST,
            .target_temp = 125.0f,      // 底部高温形成锅巴
            .temp_tolerance = 5.0f,
            .duration_sec = 480,        // 8分钟
            .power_level = 70,          // 中高火
            .exit_on_temp = 0,
            .exit_on_time = 1
        },
        // 焖饭
        {
            .stage = STAGE_BRAISE,
            .target_temp = 90.0f,
            .temp_tolerance = 5.0f,
            .duration_sec = 300,
            .power_level = 0,           // 关火焖
            .exit_on_temp = 0,
            .exit_on_time = 1
        },
        // 保温
        {
            .stage = STAGE_KEEP_WARM,
            .target_temp = 65.0f,
            .temp_tolerance = 5.0f,
            .duration_sec = 0,
            .power_level = 5,
            .exit_on_temp = 0,
            .exit_on_time = 0
        }
    },
    .total_time_min = 42
};

煲仔饭模式

煲仔饭需要先煮饭,然后加入腊肠等配料继续加热:

c 复制代码
/**
 * 煲仔饭配方
 * 特点:底部锅巴+中途可加料+酱汁焦香
 */
static const recipe_t recipe_claypot_rice = {
    .mode = MODE_CLAYPOT_RICE,
    .name = "煲仔饭",
    .num_stages = 8,
    .stages = {
        // 预热
        {STAGE_PREHEAT, 50.0f, 3.0f, 240, 35, 1, 1},
        // 吸水
        {STAGE_SOAK, 65.0f, 5.0f, 600, 20, 0, 1},
        // 升温
        {STAGE_HEAT_UP, 100.0f, 2.0f, 480, 100, 1, 0},
        // 初次沸腾(此时可以提示加料)
        {STAGE_BOIL, 103.0f, 3.0f, 600, 80, 0, 1},
        // 加料后继续加热
        {STAGE_SIMMER, 100.0f, 3.0f, 480, 60, 0, 1},
        // 锅巴+焦香(大火收汁)
        {STAGE_CRUST, 130.0f, 5.0f, 420, 85, 0, 1},
        // 焖
        {STAGE_BRAISE, 85.0f, 5.0f, 300, 0, 0, 1},
        // 保温
        {STAGE_KEEP_WARM, 65.0f, 5.0f, 0, 5, 0, 0}
    },
    .total_time_min = 48
};

蒸蛋糕模式

蛋糕需要恒温蒸制,温度控制非常关键:

复制代码
温度(°C)
    ↑
110 │        ┌─────────────────────────────┐
    │       ╱│         恒温蒸制             │
100 │──────╱ │      (100-105°C)            │
    │     ╱  └─────────────────────────────┘
 80 │    ╱
    │   ╱ 升温
 60 │  ╱
    │ ╱
 40 │╱ 预热
    └──────┬─────────────────────────────────→ 时间
          5min           50-60min

关键点:
- 升温要平稳,避免表面过早结皮
- 蒸制温度恒定在100-105°C
- 时间根据蛋糕大小调整
- 不能沸腾过于剧烈(会导致蛋糕开裂)
c 复制代码
/**
 * 蛋糕配方
 */
static const recipe_t recipe_cake = {
    .mode = MODE_CAKE,
    .name = "蛋糕",
    .num_stages = 4,
    .stages = {
        // 预热
        {
            .stage = STAGE_PREHEAT,
            .target_temp = 60.0f,
            .temp_tolerance = 3.0f,
            .duration_sec = 180,
            .power_level = 40,
            .exit_on_temp = 1,
            .exit_on_time = 1
        },
        // 缓慢升温
        {
            .stage = STAGE_HEAT_UP,
            .target_temp = 100.0f,
            .temp_tolerance = 2.0f,
            .duration_sec = 300,        // 5分钟缓升温
            .power_level = 50,          // 中等功率,避免过快
            .exit_on_temp = 1,
            .exit_on_time = 0
        },
        // 恒温蒸制(核心阶段)
        {
            .stage = STAGE_STEAM,
            .target_temp = 102.0f,      // 略高于100°C
            .temp_tolerance = 2.0f,     // 严格控温
            .duration_sec = 3000,       // 50分钟
            .power_level = 35,          // 维持蒸汽,不要太猛
            .exit_on_temp = 0,
            .exit_on_time = 1
        },
        // 完成(不保温,需要取出)
        {
            .stage = STAGE_COMPLETE,
            .target_temp = 0.0f,
            .temp_tolerance = 0.0f,
            .duration_sec = 0,
            .power_level = 0,
            .exit_on_temp = 0,
            .exit_on_time = 0
        }
    },
    .total_time_min = 60
};

煮粥模式

粥需要长时间小火慢煮,防止溢出是关键:

c 复制代码
/**
 * 煮粥配方
 * 特点:时间长、火力小、防溢出
 */
static const recipe_t recipe_porridge = {
    .mode = MODE_PORRIDGE,
    .name = "煮粥",
    .num_stages = 5,
    .stages = {
        // 预热
        {STAGE_PREHEAT, 50.0f, 3.0f, 300, 30, 1, 1},
        // 升温
        {STAGE_HEAT_UP, 95.0f, 2.0f, 600, 80, 1, 0},
        // 沸腾(短暂,防溢)
        {STAGE_BOIL, 98.0f, 2.0f, 300, 50, 0, 1},
        // 小火慢煮(核心)
        {
            .stage = STAGE_SIMMER,
            .target_temp = 93.0f,       // 低于沸点,防溢
            .temp_tolerance = 3.0f,
            .duration_sec = 3600,       // 60分钟慢煮
            .power_level = 25,          // 小火
            .exit_on_temp = 0,
            .exit_on_time = 1
        },
        // 保温
        {STAGE_KEEP_WARM, 65.0f, 5.0f, 0, 5, 0, 0}
    },
    .total_time_min = 75
};

酸奶模式(发酵)

酸奶需要长时间恒温发酵:

c 复制代码
/**
 * 酸奶配方
 * 特点:低温恒温、时间长
 */
static const recipe_t recipe_yogurt = {
    .mode = MODE_YOGURT,
    .name = "酸奶",
    .num_stages = 3,
    .stages = {
        // 加热到发酵温度
        {
            .stage = STAGE_HEAT_UP,
            .target_temp = 42.0f,       // 发酵最佳温度
            .temp_tolerance = 1.0f,     // 精确控温
            .duration_sec = 600,
            .power_level = 20,
            .exit_on_temp = 1,
            .exit_on_time = 0
        },
        // 恒温发酵
        {
            .stage = STAGE_FERMENT,
            .target_temp = 42.0f,
            .temp_tolerance = 2.0f,
            .duration_sec = 28800,      // 8小时
            .power_level = 5,           // 极小功率维持温度
            .exit_on_temp = 0,
            .exit_on_time = 1
        },
        // 完成
        {STAGE_COMPLETE, 0.0f, 0.0f, 0, 0, 0, 0}
    },
    .total_time_min = 490    // 约8小时
};

状态机设计

主状态机

c 复制代码
/**
 * 系统主状态
 */
typedef enum {
    STATE_IDLE,             // 空闲,等待用户操作
    STATE_STANDBY,          // 待机,已选择模式
    STATE_COOKING,          // 烹饪中
    STATE_PAUSED,           // 暂停
    STATE_KEEP_WARM,        // 保温中
    STATE_COMPLETE,         // 完成
    STATE_ERROR             // 错误
} system_state_t;

/**
 * 系统事件
 */
typedef enum {
    EVENT_NONE,
    EVENT_START,            // 开始按键
    EVENT_CANCEL,           // 取消按键
    EVENT_MODE_SELECT,      // 模式选择
    EVENT_TIMER_SET,        // 预约设置
    EVENT_LID_OPEN,         // 开盖
    EVENT_LID_CLOSE,        // 合盖
    EVENT_STAGE_COMPLETE,   // 阶段完成
    EVENT_TEMP_ALARM,       // 温度异常
    EVENT_TIMEOUT,          // 超时
    EVENT_POWER_FAIL        // 断电
} system_event_t;

/**
 * 系统上下文
 */
typedef struct {
    system_state_t state;
    cooking_mode_t mode;
    uint8_t current_stage;
    uint32_t stage_start_time;
    uint32_t cook_start_time;
    
    // 温度
    float temp_bottom;
    float temp_side;
    float temp_lid;
    
    // 目标
    float target_temp;
    uint8_t target_power;
    
    // 预约
    uint8_t timer_enabled;
    uint32_t timer_target;
    
    // 错误
    uint8_t error_code;
    
} cooker_context_t;

static cooker_context_t g_ctx;

状态转换

c 复制代码
/**
 * 状态机转换表
 */
typedef struct {
    system_state_t current;
    system_event_t event;
    system_state_t next;
    void (*action)(void);
} state_transition_t;

// 前向声明动作函数
static void action_start_cooking(void);
static void action_stop_cooking(void);
static void action_pause(void);
static void action_resume(void);
static void action_enter_keep_warm(void);
static void action_handle_error(void);

static const state_transition_t transitions[] = {
    // 空闲状态
    {STATE_IDLE,      EVENT_MODE_SELECT,   STATE_STANDBY,   NULL},
    
    // 待机状态
    {STATE_STANDBY,   EVENT_START,         STATE_COOKING,   action_start_cooking},
    {STATE_STANDBY,   EVENT_CANCEL,        STATE_IDLE,      NULL},
    {STATE_STANDBY,   EVENT_MODE_SELECT,   STATE_STANDBY,   NULL},
    
    // 烹饪状态
    {STATE_COOKING,   EVENT_CANCEL,        STATE_IDLE,      action_stop_cooking},
    {STATE_COOKING,   EVENT_LID_OPEN,      STATE_PAUSED,    action_pause},
    {STATE_COOKING,   EVENT_STAGE_COMPLETE,STATE_COOKING,   NULL},  // 内部处理
    {STATE_COOKING,   EVENT_TEMP_ALARM,    STATE_ERROR,     action_handle_error},
    
    // 暂停状态
    {STATE_PAUSED,    EVENT_LID_CLOSE,     STATE_COOKING,   action_resume},
    {STATE_PAUSED,    EVENT_CANCEL,        STATE_IDLE,      action_stop_cooking},
    {STATE_PAUSED,    EVENT_TIMEOUT,       STATE_ERROR,     action_handle_error},
    
    // 保温状态
    {STATE_KEEP_WARM, EVENT_CANCEL,        STATE_IDLE,      action_stop_cooking},
    {STATE_KEEP_WARM, EVENT_START,         STATE_COOKING,   action_start_cooking},
    
    // 完成状态
    {STATE_COMPLETE,  EVENT_CANCEL,        STATE_IDLE,      NULL},
    {STATE_COMPLETE,  EVENT_START,         STATE_KEEP_WARM, action_enter_keep_warm},
    
    // 错误状态
    {STATE_ERROR,     EVENT_CANCEL,        STATE_IDLE,      NULL},
};

#define NUM_TRANSITIONS (sizeof(transitions) / sizeof(transitions[0]))

/**
 * 状态机处理
 */
void state_machine_process(system_event_t event)
{
    for (int i = 0; i < NUM_TRANSITIONS; i++) {
        if (transitions[i].current == g_ctx.state && 
            transitions[i].event == event) {
            
            // 执行动作
            if (transitions[i].action) {
                transitions[i].action();
            }
            
            // 状态转换
            system_state_t old_state = g_ctx.state;
            g_ctx.state = transitions[i].next;
            
            printf("[FSM] %d -> %d (event: %d)\n", old_state, g_ctx.state, event);
            
            // 更新显示
            display_update_state(g_ctx.state);
            
            return;
        }
    }
    
    // 未找到匹配的转换
    printf("[FSM] No transition for state=%d, event=%d\n", g_ctx.state, event);
}

烹饪阶段控制

c 复制代码
/**
 * 配方管理
 */
static const recipe_t* recipes[] = {
    &recipe_standard_rice,
    &recipe_firewood_rice,
    &recipe_claypot_rice,
    &recipe_porridge,
    &recipe_cake,
    &recipe_yogurt,
    // ... 其他配方
};

static const recipe_t* g_current_recipe = NULL;

/**
 * 开始烹饪
 */
static void action_start_cooking(void)
{
    // 获取当前模式的配方
    g_current_recipe = recipes[g_ctx.mode];
    
    if (g_current_recipe == NULL) {
        g_ctx.error_code = ERR_INVALID_MODE;
        g_ctx.state = STATE_ERROR;
        return;
    }
    
    // 初始化烹饪参数
    g_ctx.current_stage = 0;
    g_ctx.cook_start_time = get_tick_ms();
    g_ctx.stage_start_time = g_ctx.cook_start_time;
    
    // 应用第一阶段参数
    apply_stage_config(&g_current_recipe->stages[0]);
    
    printf("[COOK] Started: %s\n", g_current_recipe->name);
    printf("[COOK] Stage 0: %d, target=%.1f°C, duration=%ds\n",
           g_current_recipe->stages[0].stage,
           g_current_recipe->stages[0].target_temp,
           g_current_recipe->stages[0].duration_sec);
    
    // 开启加热
    heater_enable(1);
    
    // 更新显示
    display_show_cooking(g_current_recipe->name, 
                         g_current_recipe->total_time_min);
}

/**
 * 应用阶段配置
 */
static void apply_stage_config(const stage_config_t *stage)
{
    g_ctx.target_temp = stage->target_temp;
    g_ctx.target_power = stage->power_level;
    
    // 更新PID目标
    pid_set_target(stage->target_temp);
}

/**
 * 检查阶段是否完成
 */
static int check_stage_complete(const stage_config_t *stage)
{
    uint32_t elapsed = get_tick_ms() - g_ctx.stage_start_time;
    uint32_t duration_ms = stage->duration_sec * 1000;
    
    // 时间条件
    if (stage->exit_on_time && elapsed >= duration_ms) {
        return 1;
    }
    
    // 温度条件
    if (stage->exit_on_temp) {
        float temp_error = g_ctx.temp_bottom - stage->target_temp;
        if (fabsf(temp_error) <= stage->temp_tolerance) {
            return 1;
        }
    }
    
    return 0;
}

/**
 * 进入下一阶段
 */
static void advance_to_next_stage(void)
{
    g_ctx.current_stage++;
    
    if (g_ctx.current_stage >= g_current_recipe->num_stages) {
        // 所有阶段完成
        cooking_complete();
        return;
    }
    
    const stage_config_t *next = &g_current_recipe->stages[g_ctx.current_stage];
    
    g_ctx.stage_start_time = get_tick_ms();
    apply_stage_config(next);
    
    printf("[COOK] Stage %d: %d, target=%.1f°C, duration=%ds\n",
           g_ctx.current_stage,
           next->stage,
           next->target_temp,
           next->duration_sec);
    
    // 特殊阶段处理
    switch (next->stage) {
    case STAGE_KEEP_WARM:
        g_ctx.state = STATE_KEEP_WARM;
        buzzer_beep(3);  // 提示音
        display_show_keep_warm();
        break;
        
    case STAGE_COMPLETE:
        cooking_complete();
        break;
        
    case STAGE_CRUST:
        // 锅巴阶段,可以播放特殊提示
        display_show_message("正在形成锅巴...");
        break;
        
    default:
        break;
    }
}

/**
 * 烹饪完成
 */
static void cooking_complete(void)
{
    heater_enable(0);
    g_ctx.state = STATE_COMPLETE;
    
    uint32_t total_time = (get_tick_ms() - g_ctx.cook_start_time) / 1000;
    
    printf("[COOK] Complete! Total time: %d:%02d\n", 
           total_time / 60, total_time % 60);
    
    buzzer_melody_complete();
    display_show_complete();
}

/**
 * 烹饪主循环(定时器中调用,如每100ms)
 */
void cooking_process(void)
{
    if (g_ctx.state != STATE_COOKING && g_ctx.state != STATE_KEEP_WARM) {
        return;
    }
    
    // 读取温度
    g_ctx.temp_bottom = read_temperature(SENSOR_BOTTOM);
    g_ctx.temp_side = read_temperature(SENSOR_SIDE);
    g_ctx.temp_lid = read_temperature(SENSOR_LID);
    
    // 安全检查
    if (g_ctx.temp_bottom > TEMP_MAX_SAFE) {
        heater_enable(0);
        g_ctx.error_code = ERR_OVER_TEMP;
        state_machine_process(EVENT_TEMP_ALARM);
        return;
    }
    
    // 获取当前阶段
    const stage_config_t *stage = &g_current_recipe->stages[g_ctx.current_stage];
    
    // 温度控制
    float power = temperature_control(stage);
    heater_set_power(power);
    
    // 检查阶段完成
    if (check_stage_complete(stage)) {
        advance_to_next_stage();
    }
    
    // 更新显示
    update_cooking_display();
}

温度控制算法

PID控制器

c 复制代码
/**
 * PID控制器
 */
typedef struct {
    float kp;               // 比例系数
    float ki;               // 积分系数
    float kd;               // 微分系数
    
    float target;           // 目标温度
    float integral;         // 积分累积
    float prev_error;       // 上次误差
    float integral_max;     // 积分限幅
    float output_min;       // 输出下限
    float output_max;       // 输出上限
    
    uint32_t last_time;
} pid_controller_t;

static pid_controller_t g_pid = {
    .kp = 8.0f,
    .ki = 0.5f,
    .kd = 2.0f,
    .integral_max = 50.0f,
    .output_min = 0.0f,
    .output_max = 100.0f
};

/**
 * PID计算
 */
float pid_compute(pid_controller_t *pid, float current_temp)
{
    uint32_t now = get_tick_ms();
    float dt = (now - pid->last_time) / 1000.0f;
    pid->last_time = now;
    
    if (dt <= 0 || dt > 1.0f) {
        dt = 0.1f;  // 默认100ms
    }
    
    float error = pid->target - current_temp;
    
    // 积分
    pid->integral += error * dt;
    
    // 积分限幅(防止积分饱和)
    if (pid->integral > pid->integral_max) {
        pid->integral = pid->integral_max;
    } else if (pid->integral < -pid->integral_max) {
        pid->integral = -pid->integral_max;
    }
    
    // 微分
    float derivative = (error - pid->prev_error) / dt;
    pid->prev_error = error;
    
    // PID输出
    float output = pid->kp * error + 
                   pid->ki * pid->integral + 
                   pid->kd * derivative;
    
    // 输出限幅
    if (output > pid->output_max) output = pid->output_max;
    if (output < pid->output_min) output = pid->output_min;
    
    return output;
}

/**
 * 设置PID目标
 */
void pid_set_target(float target)
{
    g_pid.target = target;
    g_pid.integral = 0;  // 目标改变时清除积分
    g_pid.prev_error = 0;
}

/**
 * 根据阶段调整PID参数
 */
void pid_tune_for_stage(cooking_stage_t stage)
{
    switch (stage) {
    case STAGE_HEAT_UP:
        // 升温阶段:快速响应,允许超调
        g_pid.kp = 10.0f;
        g_pid.ki = 0.3f;
        g_pid.kd = 1.0f;
        break;
        
    case STAGE_BOIL:
        // 沸腾阶段:维持高温
        g_pid.kp = 8.0f;
        g_pid.ki = 0.5f;
        g_pid.kd = 2.0f;
        break;
        
    case STAGE_SIMMER:
    case STAGE_KEEP_WARM:
        // 保温阶段:平稳控制,避免波动
        g_pid.kp = 5.0f;
        g_pid.ki = 0.8f;
        g_pid.kd = 3.0f;
        break;
        
    case STAGE_CRUST:
        // 锅巴阶段:需要高温但不能烧焦
        g_pid.kp = 6.0f;
        g_pid.ki = 0.2f;
        g_pid.kd = 4.0f;
        break;
        
    default:
        // 默认参数
        g_pid.kp = 8.0f;
        g_pid.ki = 0.5f;
        g_pid.kd = 2.0f;
        break;
    }
}

模糊控制(高级)

对于更精细的温度控制,可以使用模糊控制:

c 复制代码
/**
 * 模糊控制器
 * 输入:温度误差(e)、误差变化率(ec)
 * 输出:功率调整量
 */

// 模糊集合定义
typedef enum {
    NB = 0,     // Negative Big
    NM,         // Negative Medium
    NS,         // Negative Small
    ZO,         // Zero
    PS,         // Positive Small
    PM,         // Positive Medium
    PB          // Positive Big
} fuzzy_set_t;

#define FUZZY_LEVELS 7

// 模糊规则表 [误差][误差变化率] -> 输出
// 行:误差(NB~PB),列:误差变化率(NB~PB)
static const int8_t fuzzy_rules[FUZZY_LEVELS][FUZZY_LEVELS] = {
    //     NB  NM  NS  ZO  PS  PM  PB   <- ec
    /*NB*/{PB, PB, PM, PM, PS, ZO, ZO},
    /*NM*/{PB, PB, PM, PS, PS, ZO, NS},
    /*NS*/{PM, PM, PM, PS, ZO, NS, NS},
    /*ZO*/{PM, PM, PS, ZO, NS, NM, NM},
    /*PS*/{PS, PS, ZO, NS, NS, NM, NM},
    /*PM*/{PS, ZO, NS, NM, NM, NM, NB},
    /*PB*/{ZO, ZO, NM, NM, NM, NB, NB}
    // ↑ e
};

// 隶属度函数参数
static const float fuzzy_centers[] = {-3, -2, -1, 0, 1, 2, 3};

/**
 * 计算隶属度(三角形隶属函数)
 */
float calc_membership(float value, float center, float width)
{
    float dist = fabsf(value - center);
    if (dist >= width) return 0;
    return 1.0f - dist / width;
}

/**
 * 模糊化
 */
void fuzzify(float value, float scale, float memberships[FUZZY_LEVELS])
{
    float normalized = value / scale;  // 归一化到[-3, 3]
    
    // 限制范围
    if (normalized < -3) normalized = -3;
    if (normalized > 3) normalized = 3;
    
    for (int i = 0; i < FUZZY_LEVELS; i++) {
        memberships[i] = calc_membership(normalized, fuzzy_centers[i], 1.0f);
    }
}

/**
 * 模糊推理
 */
float fuzzy_inference(float e_memberships[FUZZY_LEVELS], 
                       float ec_memberships[FUZZY_LEVELS])
{
    float output_memberships[FUZZY_LEVELS] = {0};
    
    // 对每条规则
    for (int i = 0; i < FUZZY_LEVELS; i++) {
        for (int j = 0; j < FUZZY_LEVELS; j++) {
            // 取小(AND)
            float strength = fminf(e_memberships[i], ec_memberships[j]);
            
            // 输出模糊集合
            int output_set = fuzzy_rules[i][j];
            
            // 取大(OR)
            if (strength > output_memberships[output_set]) {
                output_memberships[output_set] = strength;
            }
        }
    }
    
    // 解模糊(重心法)
    float numerator = 0;
    float denominator = 0;
    
    for (int i = 0; i < FUZZY_LEVELS; i++) {
        numerator += fuzzy_centers[i] * output_memberships[i];
        denominator += output_memberships[i];
    }
    
    if (denominator < 0.001f) return 0;
    return numerator / denominator;
}

/**
 * 模糊控制主函数
 */
float fuzzy_control(float target_temp, float current_temp, float *prev_temp)
{
    // 计算误差和误差变化率
    float e = target_temp - current_temp;
    float ec = current_temp - *prev_temp;  // 温度变化率(误差变化率的负值)
    *prev_temp = current_temp;
    
    // 模糊化
    float e_memberships[FUZZY_LEVELS];
    float ec_memberships[FUZZY_LEVELS];
    
    fuzzify(e, 20.0f, e_memberships);      // 误差范围±60°C
    fuzzify(-ec, 5.0f, ec_memberships);    // 变化率范围±15°C/周期
    
    // 模糊推理
    float output = fuzzy_inference(e_memberships, ec_memberships);
    
    // 输出映射到功率 (0-100%)
    float power = 50.0f + output * 16.67f;  // [-3,3] -> [0,100]
    
    if (power > 100) power = 100;
    if (power < 0) power = 0;
    
    return power;
}

综合温度控制

c 复制代码
/**
 * 温度控制策略
 */
typedef enum {
    CTRL_PID,           // PID控制
    CTRL_FUZZY,         // 模糊控制
    CTRL_BANG_BANG,     // 开关控制(简单模式)
    CTRL_HYBRID         // 混合控制
} control_strategy_t;

/**
 * 综合温度控制
 */
float temperature_control(const stage_config_t *stage)
{
    float current_temp = g_ctx.temp_bottom;
    float target_temp = stage->target_temp;
    float max_power = stage->power_level;
    
    float power = 0;
    
    // 根据阶段选择控制策略
    switch (stage->stage) {
    case STAGE_HEAT_UP:
        // 升温阶段:全功率加热直到接近目标
        if (current_temp < target_temp - 10) {
            power = max_power;
        } else {
            // 接近目标时切换到PID
            power = pid_compute(&g_pid, current_temp);
        }
        break;
        
    case STAGE_SOAK:
    case STAGE_SIMMER:
        // 恒温阶段:PID精确控制
        pid_tune_for_stage(stage->stage);
        power = pid_compute(&g_pid, current_temp);
        break;
        
    case STAGE_BOIL:
        // 沸腾阶段:维持高功率,但不超过最大
        if (current_temp < 100) {
            power = max_power;
        } else {
            power = max_power * 0.7f;  // 维持沸腾
        }
        break;
        
    case STAGE_CRUST:
        // 锅巴阶段:需要精确控制,防止烧焦
        static float prev_temp_crust = 0;
        power = fuzzy_control(target_temp, current_temp, &prev_temp_crust);
        break;
        
    case STAGE_KEEP_WARM:
        // 保温:间歇加热
        if (current_temp < target_temp - 3) {
            power = 20;
        } else if (current_temp > target_temp + 3) {
            power = 0;
        } else {
            power = 5;  // 微弱维持
        }
        break;
        
    default:
        power = pid_compute(&g_pid, current_temp);
        break;
    }
    
    // 功率限制
    if (power > max_power) power = max_power;
    if (power < 0) power = 0;
    
    return power;
}

安全保护机制

多重保护

c 复制代码
/**
 * 错误代码
 */
typedef enum {
    ERR_NONE = 0,
    ERR_OVER_TEMP,          // 过温
    ERR_SENSOR_OPEN,        // 传感器开路
    ERR_SENSOR_SHORT,       // 传感器短路
    ERR_HEATER_FAIL,        // 加热器故障
    ERR_LID_OPEN_TIMEOUT,   // 开盖超时
    ERR_DRY_BURN,           // 干烧
    ERR_POWER_FAIL,         // 电源异常
    ERR_IGBT_FAIL           // IGBT故障(IH)
} error_code_t;

/**
 * 安全参数
 */
typedef struct {
    float temp_max_bottom;      // 底部最高温度
    float temp_max_side;        // 侧面最高温度
    float temp_max_lid;         // 上盖最高温度
    float temp_rise_rate_max;   // 最大升温速率 (°C/s)
    uint16_t lid_open_timeout;  // 开盖超时 (s)
    float dry_burn_detect_temp; // 干烧检测温度
    float dry_burn_detect_rate; // 干烧检测升温速率
} safety_params_t;

static const safety_params_t safety_params = {
    .temp_max_bottom = 180.0f,      // 底部不超过180°C
    .temp_max_side = 150.0f,
    .temp_max_lid = 120.0f,
    .temp_rise_rate_max = 10.0f,    // 每秒不超过10°C
    .lid_open_timeout = 300,        // 开盖5分钟超时
    .dry_burn_detect_temp = 150.0f, // 干烧判定温度
    .dry_burn_detect_rate = 5.0f    // 干烧判定升温速率
};

/**
 * 干烧检测
 * 原理:正常煮饭时,水沸腾温度约100°C,
 * 如果温度持续上升超过这个值且上升很快,说明水烧干了
 */
typedef struct {
    float prev_temp;
    uint32_t prev_time;
    uint8_t high_temp_count;
} dry_burn_detector_t;

static dry_burn_detector_t g_dry_burn;

int detect_dry_burn(float current_temp)
{
    uint32_t now = get_tick_ms();
    float dt = (now - g_dry_burn.prev_time) / 1000.0f;
    
    if (dt > 0.1f) {
        float rate = (current_temp - g_dry_burn.prev_temp) / dt;
        g_dry_burn.prev_temp = current_temp;
        g_dry_burn.prev_time = now;
        
        // 温度高于检测阈值且上升快
        if (current_temp > safety_params.dry_burn_detect_temp &&
            rate > safety_params.dry_burn_detect_rate) {
            g_dry_burn.high_temp_count++;
            
            // 连续检测到多次认为干烧
            if (g_dry_burn.high_temp_count > 10) {
                return 1;
            }
        } else {
            g_dry_burn.high_temp_count = 0;
        }
    }
    
    return 0;
}

/**
 * 传感器故障检测
 */
int check_sensor_fault(float temp, uint16_t adc_value)
{
    // ADC值接近0:短路
    if (adc_value < 10) {
        return ERR_SENSOR_SHORT;
    }
    
    // ADC值接近最大:开路
    if (adc_value > 4085) {  // 12位ADC
        return ERR_SENSOR_OPEN;
    }
    
    // 温度不合理
    if (temp < -30 || temp > 250) {
        return ERR_SENSOR_OPEN;
    }
    
    return ERR_NONE;
}

/**
 * 综合安全检查
 */
int safety_check(void)
{
    // 1. 传感器检查
    int err = check_sensor_fault(g_ctx.temp_bottom, adc_read(ADC_CH_BOTTOM));
    if (err) return err;
    
    err = check_sensor_fault(g_ctx.temp_side, adc_read(ADC_CH_SIDE));
    if (err) return err;
    
    // 2. 过温检查
    if (g_ctx.temp_bottom > safety_params.temp_max_bottom) {
        return ERR_OVER_TEMP;
    }
    if (g_ctx.temp_side > safety_params.temp_max_side) {
        return ERR_OVER_TEMP;
    }
    
    // 3. 干烧检测(仅在煮饭模式)
    if (g_ctx.state == STATE_COOKING) {
        cooking_stage_t stage = g_current_recipe->stages[g_ctx.current_stage].stage;
        
        // 吸水和沸腾阶段检测干烧
        if (stage == STAGE_SOAK || stage == STAGE_BOIL) {
            if (detect_dry_burn(g_ctx.temp_bottom)) {
                return ERR_DRY_BURN;
            }
        }
    }
    
    // 4. 开盖超时检查
    if (g_ctx.state == STATE_PAUSED) {
        uint32_t pause_time = (get_tick_ms() - g_ctx.stage_start_time) / 1000;
        if (pause_time > safety_params.lid_open_timeout) {
            return ERR_LID_OPEN_TIMEOUT;
        }
    }
    
    return ERR_NONE;
}

/**
 * 错误处理
 */
static void action_handle_error(void)
{
    // 立即关闭加热
    heater_enable(0);
    
    // 报警
    buzzer_alarm();
    
    // 显示错误信息
    const char* error_msgs[] = {
        [ERR_NONE] = "无错误",
        [ERR_OVER_TEMP] = "E1: 温度过高",
        [ERR_SENSOR_OPEN] = "E2: 传感器开路",
        [ERR_SENSOR_SHORT] = "E3: 传感器短路",
        [ERR_HEATER_FAIL] = "E4: 加热器故障",
        [ERR_LID_OPEN_TIMEOUT] = "E5: 请合上盖子",
        [ERR_DRY_BURN] = "E6: 检测到干烧",
        [ERR_POWER_FAIL] = "E7: 电源异常",
        [ERR_IGBT_FAIL] = "E8: IGBT故障"
    };
    
    display_show_error(error_msgs[g_ctx.error_code]);
    
    printf("[ERROR] %s\n", error_msgs[g_ctx.error_code]);
}

用户界面与交互

按键处理

c 复制代码
/**
 * 按键定义
 */
typedef enum {
    KEY_NONE,
    KEY_POWER,          // 电源/取消
    KEY_START,          // 开始/确认
    KEY_MODE,           // 模式选择
    KEY_TIMER,          // 预约
    KEY_KEEP_WARM,      // 保温
    KEY_PLUS,           // +
    KEY_MINUS           // -
} key_code_t;

/**
 * 按键扫描(带消抖)
 */
static uint8_t key_state[8] = {0};
static uint8_t key_count[8] = {0};

key_code_t key_scan(void)
{
    static const uint8_t key_pins[] = {
        PIN_KEY_POWER, PIN_KEY_START, PIN_KEY_MODE,
        PIN_KEY_TIMER, PIN_KEY_WARM, PIN_KEY_PLUS, PIN_KEY_MINUS
    };
    
    key_code_t pressed = KEY_NONE;
    
    for (int i = 0; i < 7; i++) {
        uint8_t current = gpio_read(key_pins[i]) == 0;  // 低电平有效
        
        if (current && !key_state[i]) {
            key_count[i]++;
            if (key_count[i] >= 3) {  // 30ms消抖
                key_state[i] = 1;
                pressed = (key_code_t)(i + 1);
            }
        } else if (!current) {
            key_state[i] = 0;
            key_count[i] = 0;
        }
    }
    
    return pressed;
}

/**
 * 按键事件处理
 */
void handle_key_event(key_code_t key)
{
    switch (g_ctx.state) {
    case STATE_IDLE:
        if (key == KEY_MODE) {
            // 循环切换模式
            g_ctx.mode = (g_ctx.mode + 1) % MODE_COUNT;
            display_show_mode(mode_names[g_ctx.mode]);
            state_machine_process(EVENT_MODE_SELECT);
        }
        break;
        
    case STATE_STANDBY:
        switch (key) {
        case KEY_START:
            state_machine_process(EVENT_START);
            break;
        case KEY_MODE:
            g_ctx.mode = (g_ctx.mode + 1) % MODE_COUNT;
            display_show_mode(mode_names[g_ctx.mode]);
            break;
        case KEY_TIMER:
            enter_timer_setting();
            break;
        case KEY_POWER:
            state_machine_process(EVENT_CANCEL);
            break;
        default:
            break;
        }
        break;
        
    case STATE_COOKING:
        if (key == KEY_POWER) {
            // 确认取消
            if (confirm_cancel()) {
                state_machine_process(EVENT_CANCEL);
            }
        }
        break;
        
    case STATE_KEEP_WARM:
        if (key == KEY_POWER) {
            state_machine_process(EVENT_CANCEL);
        }
        break;
        
    case STATE_COMPLETE:
        if (key == KEY_KEEP_WARM) {
            state_machine_process(EVENT_START);
        } else if (key == KEY_POWER) {
            state_machine_process(EVENT_CANCEL);
        }
        break;
        
    case STATE_ERROR:
        if (key == KEY_POWER) {
            state_machine_process(EVENT_CANCEL);
        }
        break;
        
    default:
        break;
    }
}

显示更新

c 复制代码
/**
 * 显示内容
 */
typedef struct {
    char line1[20];         // 第一行(模式/状态)
    char line2[20];         // 第二行(时间/温度)
    uint8_t icon_heat;      // 加热图标
    uint8_t icon_warm;      // 保温图标
    uint8_t icon_timer;     // 预约图标
} display_content_t;

/**
 * 更新烹饪显示
 */
void update_cooking_display(void)
{
    display_content_t disp;
    
    // 第一行:模式名称
    snprintf(disp.line1, sizeof(disp.line1), "%s", 
             g_current_recipe->name);
    
    // 第二行:剩余时间
    uint32_t elapsed = (get_tick_ms() - g_ctx.cook_start_time) / 1000;
    uint32_t total = g_current_recipe->total_time_min * 60;
    int32_t remaining = total - elapsed;
    
    if (remaining < 0) remaining = 0;
    
    snprintf(disp.line2, sizeof(disp.line2), "%02d:%02d", 
             remaining / 60, remaining % 60);
    
    // 图标
    disp.icon_heat = (g_ctx.target_power > 0);
    disp.icon_warm = (g_ctx.state == STATE_KEEP_WARM);
    disp.icon_timer = g_ctx.timer_enabled;
    
    display_update(&disp);
}

/**
 * 数码管/LCD显示驱动
 */
void display_update(display_content_t *content)
{
    // 假设使用段码LCD
    lcd_clear();
    lcd_set_cursor(0, 0);
    lcd_print(content->line1);
    lcd_set_cursor(1, 0);
    lcd_print(content->line2);
    
    // 更新图标
    lcd_set_icon(ICON_HEAT, content->icon_heat);
    lcd_set_icon(ICON_WARM, content->icon_warm);
    lcd_set_icon(ICON_TIMER, content->icon_timer);
}

完整主程序

c 复制代码
/**
 * main.c - 电饭锅主程序
 */

#include "cooker.h"
#include "display.h"
#include "heater.h"
#include "sensor.h"
#include "buzzer.h"

/**
 * 系统初始化
 */
void system_init(void)
{
    // 时钟初始化
    clock_init();
    
    // GPIO初始化
    gpio_init();
    
    // ADC初始化(温度传感器)
    adc_init();
    
    // 定时器初始化
    timer_init();
    
    // 显示初始化
    display_init();
    
    // 加热器初始化
    heater_init();
    
    // 蜂鸣器初始化
    buzzer_init();
    
    // 状态初始化
    memset(&g_ctx, 0, sizeof(g_ctx));
    g_ctx.state = STATE_IDLE;
    g_ctx.mode = MODE_STANDARD_RICE;
    
    // 显示开机画面
    display_show_logo();
    delay_ms(1000);
    
    // 开机自检
    if (self_test() != 0) {
        g_ctx.state = STATE_ERROR;
        display_show_error("自检失败");
        return;
    }
    
    display_show_idle();
    printf("[SYSTEM] Initialized\n");
}

/**
 * 开机自检
 */
int self_test(void)
{
    printf("[TEST] Starting self-test...\n");
    
    // 检测传感器
    float temp = read_temperature(SENSOR_BOTTOM);
    if (temp < -20 || temp > 100) {
        printf("[TEST] Bottom sensor fail: %.1f\n", temp);
        g_ctx.error_code = ERR_SENSOR_OPEN;
        return -1;
    }
    
    temp = read_temperature(SENSOR_SIDE);
    if (temp < -20 || temp > 100) {
        printf("[TEST] Side sensor fail: %.1f\n", temp);
        g_ctx.error_code = ERR_SENSOR_OPEN;
        return -1;
    }
    
    // 可以加入加热器测试(短暂通电检测电流)
    // ...
    
    printf("[TEST] Self-test passed\n");
    return 0;
}

/**
 * 10ms定时器中断
 */
void TIM3_IRQHandler(void)
{
    if (timer_get_flag(TIM3)) {
        timer_clear_flag(TIM3);
        
        static uint8_t tick_10ms = 0;
        tick_10ms++;
        
        // 10ms: 按键扫描
        key_code_t key = key_scan();
        if (key != KEY_NONE) {
            handle_key_event(key);
        }
        
        // 100ms: 温度控制和烹饪逻辑
        if (tick_10ms >= 10) {
            tick_10ms = 0;
            cooking_process();
            
            // 安全检查
            int err = safety_check();
            if (err != ERR_NONE) {
                g_ctx.error_code = err;
                state_machine_process(EVENT_TEMP_ALARM);
            }
        }
    }
}

/**
 * 主函数
 */
int main(void)
{
    system_init();
    
    while (1) {
        // 主循环可以处理低优先级任务
        
        // 空闲时降低功耗
        if (g_ctx.state == STATE_IDLE) {
            enter_low_power_mode();
        }
        
        // 调试输出
        #ifdef DEBUG
        static uint32_t last_debug = 0;
        if (get_tick_ms() - last_debug > 1000) {
            last_debug = get_tick_ms();
            
            printf("[DBG] State:%d Stage:%d Temp:%.1f/%.1f/%.1f Power:%d%%\n",
                   g_ctx.state, g_ctx.current_stage,
                   g_ctx.temp_bottom, g_ctx.temp_side, g_ctx.temp_lid,
                   g_ctx.target_power);
        }
        #endif
    }
}

调试技巧

温度曲线记录

c 复制代码
/**
 * 温度曲线记录(用于调试和优化配方)
 */
#define LOG_SIZE 1000

typedef struct {
    uint32_t timestamp;
    float temp_bottom;
    float temp_side;
    uint8_t power;
    uint8_t stage;
} temp_log_t;

static temp_log_t g_temp_log[LOG_SIZE];
static uint16_t g_log_index = 0;

void log_temperature(void)
{
    if (g_log_index >= LOG_SIZE) return;
    
    g_temp_log[g_log_index].timestamp = get_tick_ms() - g_ctx.cook_start_time;
    g_temp_log[g_log_index].temp_bottom = g_ctx.temp_bottom;
    g_temp_log[g_log_index].temp_side = g_ctx.temp_side;
    g_temp_log[g_log_index].power = g_ctx.target_power;
    g_temp_log[g_log_index].stage = g_ctx.current_stage;
    g_log_index++;
}

void dump_temperature_log(void)
{
    printf("Time,TempBottom,TempSide,Power,Stage\n");
    for (int i = 0; i < g_log_index; i++) {
        printf("%u,%.1f,%.1f,%d,%d\n",
               g_temp_log[i].timestamp,
               g_temp_log[i].temp_bottom,
               g_temp_log[i].temp_side,
               g_temp_log[i].power,
               g_temp_log[i].stage);
    }
}

配方参数在线调整

c 复制代码
/**
 * 串口命令调试
 */
void debug_command_handler(char *cmd)
{
    float value;
    
    if (sscanf(cmd, "SET_TEMP %f", &value) == 1) {
        g_pid.target = value;
        printf("Target temp set to %.1f\n", value);
    }
    else if (sscanf(cmd, "SET_KP %f", &value) == 1) {
        g_pid.kp = value;
        printf("Kp set to %.2f\n", value);
    }
    else if (sscanf(cmd, "SET_KI %f", &value) == 1) {
        g_pid.ki = value;
        printf("Ki set to %.2f\n", value);
    }
    else if (sscanf(cmd, "SET_KD %f", &value) == 1) {
        g_pid.kd = value;
        printf("Kd set to %.2f\n", value);
    }
    else if (strcmp(cmd, "DUMP_LOG") == 0) {
        dump_temperature_log();
    }
    else if (strcmp(cmd, "STATUS") == 0) {
        printf("State:%d Mode:%d Stage:%d\n", 
               g_ctx.state, g_ctx.mode, g_ctx.current_stage);
        printf("Temp: B=%.1f S=%.1f L=%.1f\n",
               g_ctx.temp_bottom, g_ctx.temp_side, g_ctx.temp_lid);
        printf("PID: Kp=%.2f Ki=%.2f Kd=%.2f\n",
               g_pid.kp, g_pid.ki, g_pid.kd);
    }
}

总结

智能电饭锅控制系统的核心技术点:

模块 关键技术
温度测量 NTC热敏电阻、ADC采样、温度换算
加热控制 PWM调功、IH电磁加热、功率调节
烹饪配方 多阶段温度曲线、时间/温度条件
状态机 多状态切换、事件驱动、异常处理
温度控制 PID算法、模糊控制、分阶段调参
安全保护 过温、干烧、传感器故障检测
用户交互 按键扫描、显示更新、预约功能

各烹饪模式的关键差异:

模式 关键特点
标准煮饭 充分吸水 + 沸腾 + 焖饭
柴火饭 短吸水 + 强火 + 高温结锅巴
煲仔饭 中途加料 + 大火收汁 + 锅巴
煮粥 长时间 + 小火 + 防溢出
蛋糕 恒温蒸制 + 精确控温
酸奶 低温 + 长时间 + 恒温发酵

这套代码框架在实际项目中经过验证,可以直接参考使用。关键是要根据实际硬件调整温度传感器参数和PID系数。

有问题欢迎评论区交流~


参考资料:

  • 《智能家电控制技术》
  • 美的/苏泊尔电饭锅专利文献
  • 《模糊控制技术》
相关推荐
linuxxx1105 小时前
request.build_absolute_uri()关于使用IP+端口
网络·python·网络协议·tcp/ip·django
晚风_END5 小时前
Linux|服务器运维|diff和vimdiff命令详解
linux·运维·服务器·开发语言·网络
ICT系统集成阿祥5 小时前
XXXX银行培训干校无线AP故障排查优化案例
运维·网络
专业开发者6 小时前
蓝牙 ® 助听器已迈入成熟应用阶段
网络·物联网
ICT技术最前线7 小时前
可视化运行管理:构建三位一体的系统运行档案规范
网络·运行档案·运行管理
Lueeee.7 小时前
换网绑定静态ip
网络·网络协议·tcp/ip
步步为营DotNet7 小时前
深度解析.NET 中IServiceCollection:构建可扩展服务体系的关键
java·网络·.net
一条闲鱼_mytube8 小时前
CI/CD: 金丝雀发布 Argo Rollouts 用户指南
网络
夜来小雨8 小时前
SRv6知识点
运维·网络