蓝桥杯嵌入式备赛:状态机重构电梯调度程序的工程实践

在嵌入式系统开发中,状态机(Finite State Machine,FSM)是一种强大的设计模式,特别适合处理具有明确状态转换逻辑的系统。蓝桥杯嵌入式竞赛中的电梯调度问题,正是状态机应用的典型场景。本文将从一个资深嵌入式工程师的角度,分享如何用状态机思想重构第八届省赛的电梯调度程序,提升代码的可维护性和可扩展性。

1. 状态机设计基础

状态机由三个核心要素构成:状态集合、事件集合和转移规则。在电梯控制系统中,这些要素可以直观地映射到实际业务逻辑:

  • 状态集合 :包括空闲(IDLE)、上行(UP)、下行(DOWN)、开门(OPENING)、关门(CLOSING)、等待(WAITING)等
  • 事件集合 :包含楼层按键事件(FLOOR_BUTTON)、到达目标楼层事件(ARRIVAL)、定时器超时事件(TIMEOUT)等
  • 转移规则 :定义在特定状态下,当某个事件发生时,系统如何转换到新状态
typedef enum {
    STATE_IDLE,
    STATE_UP,
    STATE_DOWN,
    STATE_OPENING,
    STATE_CLOSING,
    STATE_WAITING
} ElevatorState;

typedef enum {
    EVT_FLOOR_BUTTON,
    EVT_ARRIVAL,
    EVT_TIMEOUT
} ElevatorEvent;

与传统标志位控制相比,状态机具有明显优势:

对比维度 标志位控制 状态机控制
代码可读性 逻辑分散,难以追踪 状态集中管理,流程清晰
可维护性 修改一处可能影响全局 状态独立,修改影响局部
扩展性 新增功能需重构逻辑 只需添加新状态和转移
调试难度 标志位组合爆炸,难排查 当前状态明确,易追踪

2. 电梯状态机建模

2.1 状态定义与转换

基于题目要求,我们首先建立电梯的核心状态模型:

  1. IDLE :电梯静止在某一楼层,等待用户输入
  2. WAITING :已接收用户指令,等待1秒后开始运行
  3. UP/DOWN :电梯正在上行或下行
  4. OPENING :到达目标楼层,正在开门
  5. CLOSING :完成开门,正在关门

状态转换图如下:

[IDLE] -- FLOOR_BUTTON --> [WAITING] -- TIMEOUT(1s) --> [UP/DOWN]
[UP/DOWN] -- ARRIVAL --> [OPENING] -- TIMEOUT(2s) --> [CLOSING]
[CLOSING] -- TIMEOUT(4s) --> [IDLE]

2.2 事件处理机制

在状态机实现中,事件处理是核心逻辑。我们采用事件队列机制:

#define MAX_EVENTS 10

typedef struct {
    ElevatorEvent events[MAX_EVENTS];
    uint8_t head;
    uint8_t tail;
} EventQueue;

void enqueueEvent(EventQueue *q, ElevatorEvent evt) {
    if ((q->tail + 1) % MAX_EVENTS != q->head) {
        q->events[q->tail] = evt;
        q->tail = (q->tail + 1) % MAX_EVENTS;
    }
}

ElevatorEvent dequeueEvent(EventQueue *q) {
    ElevatorEvent evt = EVT_NONE;
    if (q->head != q->tail) {
        evt = q->events[q->head];
        q->head = (q->head + 1) % MAX_EVENTS;
    }
    return evt;
}

3. 状态机实现细节

3.1 状态转移表实现

使用状态转移表可以清晰地表达状态转换逻辑:

typedef struct {
    ElevatorState currentState;
    ElevatorEvent event;
    ElevatorState nextState;
    void (*action)(void);
} StateTransition;

const StateTransition transitionTable[] = {
    {STATE_IDLE, EVT_FLOOR_BUTTON, STATE_WAITING, startWaitingTimer},
    {STATE_WAITING, EVT_TIMEOUT, STATE_UP, startMovingUp},
    {STATE_WAITING, EVT_TIMEOUT, STATE_DOWN, startMovingDown},
    {STATE_UP, EVT_ARRIVAL, STATE_OPENING, stopElevator},
    {STATE_DOWN, EVT_ARRIVAL, STATE_OPENING, stopElevator},
    {STATE_OPENING, EVT_TIMEOUT, STATE_CLOSING, startClosingDoor},
    {STATE_CLOSING, EVT_TIMEOUT, STATE_IDLE, completeCycle}
};

3.2 主循环与状态处理

主循环负责处理事件和状态转移:

void elevatorMainLoop(void) {
    static ElevatorState currentState = STATE_IDLE;
    EventQueue eventQueue = {0};
    
    while(1) {
        ElevatorEvent evt = dequeueEvent(&eventQueue);
        if (evt != EVT_NONE) {
            for (int i = 0; i < sizeof(transitionTable)/sizeof(transitionTable[0]); i++) {
                if (transitionTable[i].currentState == currentState && 
                    transitionTable[i].event == evt) {
                    if (transitionTable[i].action) {
                        transitionTable[i].action();
                    }
                    currentState = transitionTable[i].nextState;
                    break;
                }
            }
        }
        // 其他系统任务
        HAL_Delay(10);
    }
}

4. 关键功能实现

4.1 楼层调度算法

在状态机框架下实现SCAN电梯调度算法:

  1. 收集所有上行和下行请求
  2. 按照当前方向处理同方向请求
  3. 到达端点后反向处理剩余请求
void updateTargetFloors(void) {
    if (currentDirection == DIR_UP) {
        // 找出所有大于当前楼层的目标
        for (int i = currentFloor + 1; i <= MAX_FLOOR; i++) {
            if (floorRequests[i]) {
                addTargetFloor(i);
            }
        }
    } else {
        // 找出所有小于当前楼层的目标
        for (int i = currentFloor - 1; i >= MIN_FLOOR; i--) {
            if (floorRequests[i]) {
                addTargetFloor(i);
            }
        }
    }
}

4.2 定时器管理

使用硬件定时器处理各种超时事件:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
    if (htim == &htim3) {
        static uint32_t counter = 0;
        counter++;
        
        // 1秒等待超时
        if (currentState == STATE_WAITING && counter >= 1000/10) {
            enqueueEvent(&eventQueue, EVT_TIMEOUT);
            counter = 0;
        }
        
        // 2秒开门超时
        if (currentState == STATE_OPENING && counter >= 2000/10) {
            enqueueEvent(&eventQueue, EVT_TIMEOUT);
            counter = 0;
        }
    }
}

4.3 外设控制集成

将LED、按键等外设控制集成到状态机中:

void updateFloorIndicator(uint8_t floor) {
    // 关闭所有楼层LED
    HAL_GPIO_WritePin(F1_LED_GPIO_Port, F1_LED_Pin, GPIO_PIN_RESET);
    // ...其他楼层LED
    
    // 点亮当前楼层LED
    switch(floor) {
        case 1: HAL_GPIO_WritePin(F1_LED_GPIO_Port, F1_LED_Pin, GPIO_PIN_SET); break;
        // ...其他楼层
    }
    
    // 更新LCD显示
    char str[20];
    sprintf(str, " %d", floor);
    LCD_DisplayStringLine(Line4, str);
}

5. 调试与优化技巧

5.1 状态追踪调试

添加状态日志输出帮助调试:

const char* stateToString(ElevatorState state) {
    switch(state) {
        case STATE_IDLE: return "IDLE";
        case STATE_WAITING: return "WAITING";
        // ...其他状态
        default: return "UNKNOWN";
    }
}

void logStateTransition(ElevatorState oldState, ElevatorState newState) {
    char logMsg[50];
    sprintf(logMsg, "State change: %s -> %s", 
            stateToString(oldState), stateToString(newState));
    debugUartSend(logMsg);
}

5.2 内存优化

对于资源受限的嵌入式系统,优化状态机内存使用:

  1. 使用位域压缩状态标志
  2. 合理设计事件队列大小
  3. 使用const修饰状态转移表节省RAM
typedef struct {
    uint8_t currentFloor : 3;  // 使用3位表示1-4层
    uint8_t direction : 1;     // 0=down, 1=up
    uint8_t state : 3;         // 主要状态编码
} CompactElevatorState;

5.3 实时性保障

确保状态机响应实时性:

  1. 关键事件使用中断触发
  2. 长耗时操作分步执行
  3. 状态处理函数保持简短
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
    if (GPIO_Pin == F1_Pin) {
        enqueueEvent(&eventQueue, EVT_FLOOR_BUTTON);
        floorRequests[1] = 1;
    }
    // ...处理其他按键
}

6. 工程实践建议

在实际项目中应用状态机时,有几个经验值得分享:

  1. 状态粒度把控 :状态不是越多越好,也不是越少越好。我通常建议每个状态对应一个明确的"行为模式",比如"正在上行"是一个状态,而不需要把"上行中经过每层"都作为独立状态。

  2. 事件设计原则 :事件应该代表"已经发生的事情",而不是"应该发生的事情"。例如"按键按下"是事件,而"需要去3楼"是状态机内部的判断逻辑。

  3. 调试技巧 :在LCD上实时显示当前状态和最近事件,可以大幅提高调试效率。我在实际项目中会保留一个调试界面,即使产品发布后也很有用。

  4. 性能考量 :在STM32F103这类资源有限的MCU上,状态机的实现要尽量轻量。避免在状态处理函数中进行复杂计算,必要时可以使用查表法优化性能。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐