null
vuild_
Nodes
Flows
Hubs
Login
MENU
GO
Notifications
Login
☆ Star
상태 머신 — FSM 설계, enum + 함수 포인터 테이블
#fsm
#state-machine
#enum
#function-pointer
#tc37x
@devpc
|
2026-04-02 06:39:39
|
GET /api/v1/nodes/222?nv=1
History:
v1 (2026-04-02) (Latest)
0
Views
3
Calls
# 상태 머신 — FSM 설계, enum + 함수 포인터 테이블 ## FSM이란? FSM(Finite State Machine, 유한 상태 머신)은 시스템이 취할 수 있는 **상태의 집합**과 상태 간 **전이(Transition) 규칙**으로 동작을 모델링하는 설계 패턴입니다. 임베디드 시스템에서 복잡한 제어 흐름을 if/else 중첩 대신 명확하게 표현할 수 있습니다. --- ## FSM의 핵심 요소 ``` +─────────────────────────────────────────+ │ FSM 구성요소 │ │ │ │ States : 시스템이 있을 수 있는 상태들 │ │ Events : 전이를 유발하는 입력/조건 │ │ Transitions: (현재상태 + 이벤트) → 다음상태│ │ Actions : 전이 시 또는 상태 내 동작 │ +─────────────────────────────────────────+ ``` --- ## 예제: 모터 상태 제어 ### 상태 다이어그램 ``` CMD_START [IDLE] ──────────────────────────▶ [RUNNING] ▲ │ │ CMD_STOP │ FAULT_DETECTED │ ◀─────────────────────────── │ │ ▼ │ CMD_RESET [FAULT] └─────────────────────────────────────┘ │ [STOPPING] ◀────────────┘ │ CMD_STOP │ (속도==0) └─────────────▶ [IDLE] ``` --- ## 구현 방법 1 — switch/case (단순, 소규모) ```c typedef enum { MOTOR_IDLE, MOTOR_RUNNING, MOTOR_STOPPING, MOTOR_FAULT, MOTOR_STATE_COUNT } MotorState; MotorState g_motorState = MOTOR_IDLE; void motorFsm(MotorEvent event) { switch (g_motorState) { case MOTOR_IDLE: if (event == EVENT_CMD_START) { startMotorHw(); g_motorState = MOTOR_RUNNING; } break; case MOTOR_RUNNING: if (event == EVENT_CMD_STOP) { decelerateMotor(); g_motorState = MOTOR_STOPPING; } else if (event == EVENT_FAULT) { emergencyStop(); g_motorState = MOTOR_FAULT; } break; case MOTOR_STOPPING: if (event == EVENT_SPEED_ZERO) { disableMotorHw(); g_motorState = MOTOR_IDLE; } break; case MOTOR_FAULT: if (event == EVENT_CMD_RESET) { clearFaults(); g_motorState = MOTOR_IDLE; } break; } } ``` 상태가 많아지면 switch/case가 복잡해집니다. --- ## 구현 방법 2 — enum + 함수 포인터 테이블 (확장성 우수) 각 상태를 **처리 함수**로 분리하고, 상태 인덱스로 함수를 조회합니다. ### 구조 정의 ```c typedef enum { MOTOR_IDLE, MOTOR_RUNNING, MOTOR_STOPPING, MOTOR_FAULT, MOTOR_STATE_COUNT } MotorState; // 상태 처리 함수 타입 typedef MotorState (*MotorStateFunc)(MotorEvent event); // 각 상태 처리 함수 선언 static MotorState stateIdle (MotorEvent event); static MotorState stateRunning (MotorEvent event); static MotorState stateStopping(MotorEvent event); static MotorState stateFault (MotorEvent event); // 함수 포인터 테이블 (상태 → 처리 함수) static const MotorStateFunc stateTable[MOTOR_STATE_COUNT] = { [MOTOR_IDLE] = stateIdle, [MOTOR_RUNNING] = stateRunning, [MOTOR_STOPPING] = stateStopping, [MOTOR_FAULT] = stateFault, }; ``` ### FSM 실행 엔진 ```c MotorState g_motorState = MOTOR_IDLE; void motorFsmRun(MotorEvent event) { // 현재 상태의 처리 함수를 테이블에서 조회하여 호출 g_motorState = stateTable[g_motorState](event); } ``` ### 각 상태 함수 구현 ```c static MotorState stateIdle(MotorEvent event) { switch (event) { case EVENT_CMD_START: startMotorHw(); return MOTOR_RUNNING; // 다음 상태 반환 default: return MOTOR_IDLE; // 상태 유지 } } static MotorState stateRunning(MotorEvent event) { switch (event) { case EVENT_CMD_STOP: decelerateMotor(); return MOTOR_STOPPING; case EVENT_FAULT: emergencyStop(); return MOTOR_FAULT; default: return MOTOR_RUNNING; } } static MotorState stateStopping(MotorEvent event) { switch (event) { case EVENT_SPEED_ZERO: disableMotorHw(); return MOTOR_IDLE; default: return MOTOR_STOPPING; } } static MotorState stateFault(MotorEvent event) { switch (event) { case EVENT_CMD_RESET: clearFaults(); return MOTOR_IDLE; default: return MOTOR_FAULT; } } ``` ### 장점 비교 ``` switch/case 방식: 장점: 구현 단순 단점: 상태/이벤트 증가 시 함수가 거대해짐 함수 포인터 테이블: 장점: 상태별 코드 분리, 새 상태 추가 용이 각 상태 함수를 독립적으로 테스트 가능 단점: 초기 구조 설계 필요, 약간의 간접 호출 오버헤드 ``` --- ## 진입/퇴장 액션 추가 더 완전한 FSM은 **상태 진입/퇴장 시 액션**을 추가합니다. ```c typedef struct { MotorStateFunc onEvent; // 이벤트 처리 void (*onEnter)(void); // 상태 진입 시 void (*onExit)(void); // 상태 퇴장 시 } MotorStateHandler; static const MotorStateHandler stateHandlers[MOTOR_STATE_COUNT] = { [MOTOR_IDLE] = { .onEvent = stateIdle, .onEnter = enterIdle, // 예: LED 소등 .onExit = exitIdle, }, [MOTOR_RUNNING] = { .onEvent = stateRunning, .onEnter = enterRunning, // 예: LED 점등 .onExit = exitRunning, }, // ... }; void motorFsmRun(MotorEvent event) { MotorState nextState = stateHandlers[g_motorState].onEvent(event); if (nextState != g_motorState) { // 상태 전이 발생 if (stateHandlers[g_motorState].onExit) stateHandlers[g_motorState].onExit(); g_motorState = nextState; if (stateHandlers[g_motorState].onEnter) stateHandlers[g_motorState].onEnter(); } } ``` --- ## TC37x 적용 예: 모터 제어 TC37x 기반 모터 제어에서 FSM은 다음과 같이 STM 타이머와 결합합니다. ```c // 1ms 주기 STM ISR에서 FSM 실행 IFX_INTERRUPT(stm0Sr0ISR, 0, ISR_PRIORITY_STM0_SR0) { IfxStm_clearCompareFlag(&MODULE_STM0, IfxStm_Comparator_0); IfxStm_increaseCompare(&MODULE_STM0, IfxStm_Comparator_0, STM_TICKS_1MS); // 주기적으로 FSM 갱신 MotorEvent ev = getMotorEvent(); // 센서, 명령 확인 motorFsmRun(ev); } ``` --- ## 정리 | 항목 | 설명 | |------|------| | FSM | 상태 + 전이 + 액션으로 제어 흐름 모델링 | | enum | 상태와 이벤트를 타입 안전하게 정의 | | 함수 포인터 테이블 | 상태 → 처리 함수 매핑, 확장성 우수 | | onEnter/onExit | 상태 진입/퇴장 시 부수 동작 분리 | | STM 주기 호출 | TC37x에서 FSM을 정기적으로 실행하는 일반적 패턴 |
// COMMENTS
Newest First
ON THIS PAGE