设计一个状态机

本人也工作三个月了,感觉到了状态机的重要,想要学习状态机的设计,目前的想法如下:如果大家有好思路,或者好的教程,可以推荐给我。以下作为分析,有问题大家提出了:

第一版本

举例子, 整体的框架为:
TempTask 协调器 NetTask BatteryTask SafetyTask Worker

1.模块状态定义

每个模块有自己的枚举状态:

c 复制代码
typedef enum {
    TEMP_NORMAL,
    TEMP_HIGH
} TempState;

typedef enum {
    NET_CONNECTED,
    NET_DISCONNECTED
} NetState;

typedef enum {
    BATTERY_NORMAL,
    BATTERY_LOW,
    BATTERY_CHARGING
} BatteryState;

typedef enum {
    SAFETY_OK,
    SAFETY_ALERT
} SafetyState;

typedef enum {
    GLOBAL_RUN,
    GLOBAL_COOLING,
    GLOBAL_WAIT_NETWORK,
    GLOBAL_LOW_POWER,
    GLOBAL_SAFETY_ALERT
} GlobalState;

2.每个模块的任务和状态机

温度任务 TempTask

c 复制代码
void TempTask(void *pvParameters) {
    TempState tempState = TEMP_NORMAL;

    for (;;) {
        int temp = getTemperatureSensor();
        if (temp > 80) tempState = TEMP_HIGH;
        else tempState = TEMP_NORMAL;

        xQueueOverwrite(tempQueue, &tempState);
        vTaskDelay(pdMS_TO_TICKS(500));
    }
}

网络任务 NetTask

c 复制代码
void NetTask(void *pvParameters) {
    NetState netState = NET_CONNECTED;

    for (;;) {
        if (!isNetworkConnected()) netState = NET_DISCONNECTED;
        else netState = NET_CONNECTED;

        xQueueOverwrite(netQueue, &netState);
        vTaskDelay(pdMS_TO_TICKS(500));
    }
}

电池任务 BatteryTask

c 复制代码
void BatteryTask(void *pvParameters) {
    BatteryState batteryState = BATTERY_NORMAL;

    for (;;) {
        int level = getBatteryLevel();
        if (level < 20) batteryState = BATTERY_LOW;
        else if (isCharging()) batteryState = BATTERY_CHARGING;
        else batteryState = BATTERY_NORMAL;

        xQueueOverwrite(batteryQueue, &batteryState);
        vTaskDelay(pdMS_TO_TICKS(500));
    }
}

安全任务 SafetyTask

c 复制代码
void SafetyTask(void *pvParameters) {
    SafetyState safetyState = SAFETY_OK;

    for (;;) {
        if (!isSafetyCoverClosed()) safetyState = SAFETY_ALERT;
        else safetyState = SAFETY_OK;

        xQueueOverwrite(safetyQueue, &safetyState);
        vTaskDelay(pdMS_TO_TICKS(500));
    }
}

3.中央协调器任务 CoordinatorTask

逻辑:

  • 收集所有模块状态
  • 基于优先级做全局状态判断(先安全 → 再电量 → 再温度 → 再网络)
  • 将全局状态发送给 WorkerTask
c 复制代码
void CoordinatorTask(void *pvParameters) {
    GlobalState globalState = GLOBAL_RUN;

    TempState tempState;
    NetState netState;
    BatteryState batteryState;
    SafetyState safetyState;

    for (;;) {
        xQueuePeek(tempQueue, &tempState, 0);
        xQueuePeek(netQueue, &netState, 0);
        xQueuePeek(batteryQueue, &batteryState, 0);
        xQueuePeek(safetyQueue, &safetyState, 0);

        if (safetyState == SAFETY_ALERT) {
            globalState = GLOBAL_SAFETY_ALERT;
        }
        else if (batteryState == BATTERY_LOW) {
            globalState = GLOBAL_LOW_POWER;
        }
        else if (tempState == TEMP_HIGH) {
            globalState = GLOBAL_COOLING;
        }
        else if (netState == NET_DISCONNECTED) {
            globalState = GLOBAL_WAIT_NETWORK;
        }
        else {
            globalState = GLOBAL_RUN;
        }

        xQueueOverwrite(globalQueue, &globalState);
        vTaskDelay(pdMS_TO_TICKS(200));
    }
}

4.主业务任务 WorkerTask

c 复制代码
void WorkerTask(void *pvParameters) {
    GlobalState globalState;
    for (;;) {
        xQueueReceive(globalQueue, &globalState, portMAX_DELAY);

        switch (globalState) {
            case GLOBAL_RUN:
                printf("[Worker] 系统运行正常\n");
                break;
            case GLOBAL_COOLING:
                printf("[Worker] 冷却模式开启\n");
                break;
            case GLOBAL_WAIT_NETWORK:
                printf("[Worker] 等待网络连接...\n");
                break;
            case GLOBAL_LOW_POWER:
                printf("[Worker] 电量低,进入节能模式\n");
                break;
            case GLOBAL_SAFETY_ALERT:
                printf("[Worker] 安全警告!停止所有运行\n");
                break;
        }
    }
}

5.系统初始化 main()

c 复制代码
int main(void) {
    tempQueue    = xQueueCreate(1, sizeof(TempState));
    netQueue     = xQueueCreate(1, sizeof(NetState));
    batteryQueue = xQueueCreate(1, sizeof(BatteryState));
    safetyQueue  = xQueueCreate(1, sizeof(SafetyState));
    globalQueue  = xQueueCreate(1, sizeof(GlobalState));

    xTaskCreate(TempTask, "Temp", 512, NULL, 2, NULL);
    xTaskCreate(NetTask, "Net", 512, NULL, 2, NULL);
    xTaskCreate(BatteryTask, "Battery", 512, NULL, 2, NULL);
    xTaskCreate(SafetyTask, "Safety", 512, NULL, 2, NULL);
    xTaskCreate(CoordinatorTask, "Coordinator", 512, NULL, 2, NULL);
    xTaskCreate(WorkerTask, "Worker", 512, NULL, 2, NULL);

    vTaskStartScheduler();
    for (;;);
}

发现的缺点:

  • 在中央协调器任务中,globalState只能响应一次,且会覆盖上一个的值。如果多个任务都要切换,那么该怎么办呢?
  • 新增模块需要改中央协调器代码,不够解耦,可以用事件发布订阅(Publish/Subscribe),中央协调器不用硬改

第二版本

1.Pub/Sub设计思路

原理:

  • 发布者(Publisher):某模块检测到状态变化后,发布一个事件到公共事件队列(EventQueue)
  • 订阅者(Subscriber):任何任务都可以从公共事件队列"订阅"事件并处理

好处:

  • 减少队列数量:所有事件走一个总队列
  • 模块解耦:发布者不关心谁会处理事件
  • 易扩展:新增模块只要发布事件;新增订阅者只要监听公共队列
  • 类似RTOS Event Bus:在大型系统里是常见模式

2.事件结构定义

我们先定义一个结构体来表示事件:

c 复制代码
typedef enum {
    MODULE_TEMP,
    MODULE_NET,
    MODULE_BATTERY,
    MODULE_SAFETY
} ModuleID;

typedef enum {
    EVENT_TEMP_NORMAL,
    EVENT_TEMP_HIGH,
    EVENT_NET_CONNECTED,
    EVENT_NET_DISCONNECTED,
    EVENT_BATTERY_NORMAL,
    EVENT_BATTERY_LOW,
    EVENT_BATTERY_CHARGING,
    EVENT_SAFETY_OK,
    EVENT_SAFETY_ALERT
} EventType;

typedef struct {
    ModuleID module;  // 事件来自哪个模块
    EventType event;  // 事件类型
    uint32_t timestamp; // 时间戳(可选)
    int value;        // 额外数据(例如温度值、电量等)
} EventMessage;

3.公共事件总线(队列)

我们用一个全局队列 eventQueue:

c 复制代码
QueueHandle_t eventQueue;

因为是公共队列,所有模块都把事件扔进同一个地方。

4.1 发布者示例(温度任务)

c 复制代码
void TempTask(void *pvParameters) {
    for (;;) {
        EventMessage msg;
        msg.module = MODULE_TEMP;
        msg.value = getTemperatureSensor();
        msg.timestamp = xTaskGetTickCount();

        if (msg.value > 80) 
            msg.event = EVENT_TEMP_HIGH;
        else 
            msg.event = EVENT_TEMP_NORMAL;
        xQueueSend(eventQueue, &msg, portMAX_DELAY);
        vTaskDelay(pdMS_TO_TICKS(500));
    }
}
  • 读取传感器数据
  • 判断事件类型(高温或正常)
  • 发布事件到总队列

4.2 发布者示例(网络任务)

c 复制代码
void NetTask(void *pvParameters) {
    for (;;) {
        EventMessage msg;
        msg.module = MODULE_NET;
        msg.timestamp = xTaskGetTickCount();

        if (isNetworkConnected()) 
            msg.event = EVENT_NET_CONNECTED;
        else 
            msg.event = EVENT_NET_DISCONNECTED;

        msg.value = 0; // 网络状态用不到value
        xQueueSend(eventQueue, &msg, portMAX_DELAY);

        vTaskDelay(pdMS_TO_TICKS(500));
    }
}

5. 订阅者(中央协调器)

c 复制代码
void CoordinatorTask(void *pvParameters) {
    GlobalState globalState = GLOBAL_RUN;

    for (;;) {
        EventMessage msg;
        if (xQueueReceive(eventQueue, &msg, portMAX_DELAY)) {
            // 根据事件决定全局状态
            switch (msg.module) {
                case MODULE_TEMP:
                    if (msg.event == EVENT_TEMP_HIGH)
                        globalState = GLOBAL_COOLING;
                    else
                        globalState = GLOBAL_RUN;
                    break;

                case MODULE_NET:
                    if (msg.event == EVENT_NET_DISCONNECTED)
                        globalState = GLOBAL_WAIT_NETWORK;
                    break;

                case MODULE_BATTERY:
                    if (msg.event == EVENT_BATTERY_LOW)
                        globalState = GLOBAL_LOW_POWER;
                    break;

                case MODULE_SAFETY:
                    if (msg.event == EVENT_SAFETY_ALERT)
                        globalState = GLOBAL_SAFETY_ALERT;
                    break;
            }

            // 发布全局状态到另一个管理队列(或直接调用 Worker)
            xQueueOverwrite(globalQueue, &globalState);
        }
    }
}

6.Worker任务(业务执行)

c 复制代码
void WorkerTask(void *pvParameters) {
    GlobalState globalState;
    for (;;) {
        xQueueReceive(globalQueue, &globalState, portMAX_DELAY);

        switch (globalState) {
            case GLOBAL_RUN:
                printf("[Worker] 正常运行\n");
                break;
            case GLOBAL_COOLING:
                printf("[Worker] 冷却模式开启\n");
                break;
            case GLOBAL_WAIT_NETWORK:
                printf("[Worker] 等待网络连接...\n");
                break;
            case GLOBAL_LOW_POWER:
                printf("[Worker] 电量低,进入节能模式\n");
                break;
            case GLOBAL_SAFETY_ALERT:
                printf("[Worker] 安全警告!停止运行\n");
                break;
        }
    }
}

7. 系统初始化 main()

c 复制代码
int main(void) {
    eventQueue  = xQueueCreate(16, sizeof(EventMessage));
    globalQueue = xQueueCreate(1,  sizeof(GlobalState));

    xTaskCreate(TempTask, "Temp", 512, NULL, 2, NULL);
    xTaskCreate(NetTask, "Net", 512, NULL, 2, NULL);
    xTaskCreate(BatteryTask, "Battery", 512, NULL, 2, NULL);
    xTaskCreate(SafetyTask, "Safety", 512, NULL, 2, NULL);
    xTaskCreate(CoordinatorTask, "Coordinator", 512, NULL, 2, NULL);
    xTaskCreate(WorkerTask, "Worker", 512, NULL, 2, NULL);

    vTaskStartScheduler();
    for (;;);
}

缺点

  • 单个状态机是没有什么问题,但是如果多个任务内部也有相应的状态机呢?

第二版plus

这里主要是增加一个优先级的情况。主要是为了根据不同的优先级,允许事件插队。整体的还是和上版一样的,主要是

1. 数据结构

EventMessage 结构中加上优先级字段:

c 复制代码
typedef enum {
    EVENT_PRI_LOW = 0,      //这里
    EVENT_PRI_NORMAL,
    EVENT_PRI_HIGH
} EventPriority;

typedef enum {
    MODULE_TEMP,
    MODULE_NET,
    MODULE_BATTERY,
    MODULE_SAFETY
} ModuleID;

typedef enum {
    EVENT_TEMP_NORMAL,
    EVENT_TEMP_HIGH,
    EVENT_NET_CONNECTED,
    EVENT_NET_DISCONNECTED,
    EVENT_BATTERY_NORMAL,
    EVENT_BATTERY_LOW,
    EVENT_BATTERY_CHARGING,
    EVENT_SAFETY_OK,
    EVENT_SAFETY_ALERT
} EventType;

typedef struct {
    ModuleID module;         // 来源模块
    EventType event;         // 事件类型
    EventPriority priority;  // 事件优先级  这里
    uint32_t timestamp;      // 时间戳
    int value;               // 额外数据
} EventMessage;

2. 全局队列定义

c 复制代码
QueueHandle_t eventQueueHigh;
QueueHandle_t eventQueueNormal;
QueueHandle_t eventQueueLow;
QueueHandle_t globalQueue; // 协调器->Worker的状态队列

3. 发布者统一接口

任何模块在发布事件时只需调用这个函数,选择优先级即可:

c 复制代码
void EventBus_Publish(EventMessage *msg) {
    switch (msg->priority) {
        case EVENT_PRI_HIGH:
            xQueueSend(eventQueueHigh, msg, portMAX_DELAY);
            break;
        case EVENT_PRI_NORMAL:
            xQueueSend(eventQueueNormal, msg, portMAX_DELAY);
            break;
        case EVENT_PRI_LOW:
        default:
            xQueueSend(eventQueueLow, msg, portMAX_DELAY);
            break;
    }
}

4. 发布者任务示例

基于3来使用,给出示例:

温度任务

高温事件 → 高优,高温正常 → 低优

c 复制代码
void TempTask(void *pvParameters) {
    for (;;) {
        EventMessage msg;
        msg.module = MODULE_TEMP;
        msg.value = getTemperatureSensor();
        msg.timestamp = xTaskGetTickCount();

        if (msg.value > 80) {
            msg.event = EVENT_TEMP_HIGH;
            msg.priority = EVENT_PRI_HIGH;
        } else {
            msg.event = EVENT_TEMP_NORMAL;
            msg.priority = EVENT_PRI_LOW;
        }

        EventBus_Publish(&msg);
        vTaskDelay(pdMS_TO_TICKS(500));
    }
}

网络任务

断网 → 中优,正常连接 → 低优

c 复制代码
void NetTask(void *pvParameters) {
    for (;;) {
        EventMessage msg;
        msg.module = MODULE_NET;
        msg.timestamp = xTaskGetTickCount();

        if (isNetworkConnected()) {
            msg.event = EVENT_NET_CONNECTED;
            msg.priority = EVENT_PRI_LOW;
        } else {
            msg.event = EVENT_NET_DISCONNECTED;
            msg.priority = EVENT_PRI_NORMAL;
        }

        EventBus_Publish(&msg);
        vTaskDelay(pdMS_TO_TICKS(500));
    }
}

5. 协调器订阅逻辑(优先取高优队列)

c 复制代码
void CoordinatorTask(void *pvParameters) {
    GlobalState globalState = GLOBAL_RUN;
    EventMessage msg;

    for (;;) {
        // 按优先级顺序取事件
        if (xQueueReceive(eventQueueHigh, &msg, 0) == pdPASS ||
            xQueueReceive(eventQueueNormal, &msg, 0) == pdPASS ||
            xQueueReceive(eventQueueLow, &msg, 0) == pdPASS) {

            switch (msg.module) {
                case MODULE_TEMP:
                    if (msg.event == EVENT_TEMP_HIGH)
                        globalState = GLOBAL_COOLING;
                    else if (globalState == GLOBAL_COOLING)
                        globalState = GLOBAL_RUN;
                    break;

                case MODULE_NET:
                    if (msg.event == EVENT_NET_DISCONNECTED)
                        globalState = GLOBAL_WAIT_NETWORK;
                    else if (globalState == GLOBAL_WAIT_NETWORK)
                        globalState = GLOBAL_RUN;
                    break;

                case MODULE_BATTERY:
                    if (msg.event == EVENT_BATTERY_LOW)
                        globalState = GLOBAL_LOW_POWER;
                    else if (globalState == GLOBAL_LOW_POWER)
                        globalState = GLOBAL_RUN;
                    break;

                case MODULE_SAFETY:
                    if (msg.event == EVENT_SAFETY_ALERT)
                        globalState = GLOBAL_SAFETY_ALERT;
                    break;
            }

            // 发布状态给 Worker
            xQueueOverwrite(globalQueue, &globalState);
        }

        vTaskDelay(pdMS_TO_TICKS(50)); // 加快响应速度
    }
}

6. Worker任务保持原有逻辑

c 复制代码
void WorkerTask(void *pvParameters) {
    GlobalState globalState;
    for (;;) {
        xQueueReceive(globalQueue, &globalState, portMAX_DELAY);
        switch (globalState) {
            case GLOBAL_RUN:
                printf("[Worker] 正常运行");
                break;
            case GLOBAL_COOLING:
                printf("[Worker] 冷却模式开启");
                break;
            case GLOBAL_WAIT_NETWORK:
                printf("[Worker] 等待网络连接...\n");
                break;
            case GLOBAL_LOW_POWER:
                printf("[Worker] 电量低,进入节能模式");
                break;
            case GLOBAL_SAFETY_ALERT:
                printf("[Worker] 安全警告!停止运行");
                break;
        }
    }
}

7.系统初始化

c 复制代码
int main(void) {
    eventQueueHigh   = xQueueCreate(10, sizeof(EventMessage));
    eventQueueNormal = xQueueCreate(10, sizeof(EventMessage));
    eventQueueLow    = xQueueCreate(10, sizeof(EventMessage));
    globalQueue      = xQueueCreate(1, sizeof(GlobalState));

    xTaskCreate(TempTask, "Temp", 512, NULL, 2, NULL);
    xTaskCreate(NetTask, "Net", 512, NULL, 2, NULL);
    xTaskCreate(BatteryTask, "Battery", 512, NULL, 2, NULL);
    xTaskCreate(SafetyTask, "Safety", 512, NULL, 2, NULL);
    xTaskCreate(CoordinatorTask, "Coordinator", 512, NULL, 3, NULL);
    xTaskCreate(WorkerTask, "Worker", 512, NULL, 2, NULL);

    vTaskStartScheduler();
    for (;;);
}

改造结果

  • 三个队列:eventQueueHigh、eventQueueNormal、eventQueueLow,按优先级明确分流
  • 发布接口简单:只需决定 priority 即会丢到对应队列
  • 消费顺序明确:Coordinator 始终先取高优队列 → 中优 → 低优
  • 性能可控:不需排序,也不会阻塞高优事件

    到这里了,以后再做想法优化,同时如果大家有好的思路可以分享
相关推荐
西岸行者5 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意5 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码5 天前
嵌入式学习路线
学习
毛小茛5 天前
计算机系统概论——校验码
学习
babe小鑫5 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms5 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下5 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。5 天前
2026.2.25监控学习
学习
im_AMBER5 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J6 天前
从“Hello World“ 开始 C++
c语言·c++·学习