Skip to content

Công nghệ 9 giây

“Website hướng dẫn, thử nghiệm và giải thích công nghệ theo cách dễ hiểu cho mọi người.”

Menu
  • Home
  • Công nghệ
  • STM32
  • ESP32
  • Altium Desinger
  • Kiến thức điện máy
Menu

BÀI 11 – STATE MACHINE: TỪ C enum ĐẾN FIRMWARE STM32 THỰC SỰ

Posted on August 20, 2026August 23, 2026 by congnghe9s

BÀI 11 – STATE MACHINE: TỪ C enum ĐẾN FIRMWARE STM32 THỰC SỰ

Ở Bài 10, bạn đã học enum. Bây giờ chúng ta ghép:

  • enum
  • switch
  • if
  • biến trạng thái
  • hàm
  • struct

để tạo ra State Machine (máy trạng thái).

Đây là một trong những kiến thức quan trọng nhất khi bạn lập trình STM32 cho máy giặt, điều hòa, tủ lạnh, robot, động cơ, hệ thống công nghiệp…


1. State Machine là gì?

Hãy tưởng tượng một máy giặt.

Nó không thể làm tất cả mọi việc cùng lúc.

Nó lần lượt:

IDLE
  ↓
FILL_WATER
  ↓
WASH
  ↓
DRAIN
  ↓
RINSE
  ↓
SPIN
  ↓
FINISH

Mỗi thời điểm máy đang ở một trạng thái.

Ví dụ:

state = WASH;

Có nghĩa:

Hiện tại máy đang ở trạng thái GIẶT.

Khi điều kiện thích hợp xuất hiện:

state = DRAIN;

Máy chuyển sang trạng thái XẢ NƯỚC.

Đó chính là State Machine.


2. Tư duy quan trọng nhất

Một State Machine luôn có 3 thứ:

① STATE – Trạng thái hiện tại

Ví dụ:

IDLE
WASH
RINSE
SPIN

② INPUT – Điều kiện đầu vào

Ví dụ:

nút START
cảm biến mức nước
timer
cảm biến cửa
cảm biến lỗi

③ TRANSITION – Chuyển trạng thái

Ví dụ:

IDLE + START → WASH
WASH + timer hết → RINSE
RINSE + timer hết → SPIN
SPIN + timer hết → FINISH

3. Dùng enum tạo State

Ví dụ máy giặt:

typedef enum
{
    WASH_IDLE,
    WASH_FILL,
    WASHING,
    WASH_DRAIN,
    WASH_RINSE,
    WASH_SPIN,
    WASH_FINISH,
    WASH_ERROR

} WashState;

Sau đó:

WashState state;

Khởi tạo:

state = WASH_IDLE;

4. switch xử lý từng trạng thái

switch(state)
{
    case WASH_IDLE:

        break;

    case WASH_FILL:

        break;

    case WASHING:

        break;

    case WASH_DRAIN:

        break;

    case WASH_RINSE:

        break;

    case WASH_SPIN:

        break;

    case WASH_FINISH:

        break;

    case WASH_ERROR:

        break;
}

Đây là bộ xương của State Machine.


5. Nhưng State Machine phải chuyển trạng thái

Ví dụ:

case WASH_IDLE:

    if(start_button == 1)
    {
        state = WASH_FILL;
    }

    break;

Có nghĩa:

Đang IDLE
     ↓
nhấn START
     ↓
chuyển sang FILL

6. Trạng thái FILL

Giả sử có cảm biến mức nước:

case WASH_FILL:

    pump_water = 1;

    if(water_level_ok == 1)
    {
        pump_water = 0;
        state = WASHING;
    }

    break;

Sơ đồ:

              water_level_ok
                     │
                     ▼
WASH_FILL ─────────> WASHING

Trong thời gian chưa đủ nước:

WASH_FILL

vẫn được giữ nguyên.


7. Trạng thái WASHING

case WASHING:

    motor = 1;

    if(wash_timer_done == 1)
    {
        motor = 0;
        state = WASH_DRAIN;
    }

    break;

Tức là:

WASHING
   │
   │ timer hết
   ▼
DRAIN

8. Đây chính là firmware

Bạn có thể bắt đầu thấy sự khác biệt giữa:

“Học C”

và:

“Lập trình firmware.”

Trong C thông thường:

printf("Hello");

Trong firmware:

state = WASH_DRAIN;

và trạng thái đó quyết định phần cứng phải làm gì.


9. Một State Machine hoàn chỉnh

Ví dụ đơn giản:

typedef enum
{
    IDLE,
    RUN,
    STOP,
    ERROR

} MachineState;

MachineState state = IDLE;

Sau đó:

while(1)
{
    switch(state)
    {
        case IDLE:

            if(start == 1)
            {
                state = RUN;
            }

            break;


        case RUN:

            motor = 1;

            if(stop == 1)
            {
                motor = 0;
                state = STOP;
            }

            if(error == 1)
            {
                motor = 0;
                state = ERROR;
            }

            break;


        case STOP:

            motor = 0;

            if(start == 1)
            {
                state = RUN;
            }

            break;


        case ERROR:

            motor = 0;

            if(reset == 1)
            {
                state = IDLE;
            }

            break;
    }
}

Bạn hãy nhìn kỹ đoạn này.

Đây đã là một firmware architecture rất cơ bản.


10. State Machine giống một “bộ não”

Có thể hình dung:

             INPUT
               │
               ▼
        ┌──────────────┐
        │ STATE MACHINE│
        └──────┬───────┘
               │
               ▼
             OUTPUT

Ví dụ STM32:

Button ──────┐
             │
Sensor ──────┼──→ STATE MACHINE ──→ Motor
             │                  ├──→ Pump
Timer ───────┘                  ├──→ Valve
                                └──→ LED

Đây là kiến trúc xuất hiện rất nhiều trong hệ thống nhúng.


11. Một ví dụ cực kỳ gần với Blue Pill của bạn

Giả sử bạn muốn dùng STM32 Blue Pill điều khiển:

  • PC13 LED
  • nút nhấn
  • biến trở
  • step motor 28BYJ-48

Ta có thể thiết kế:

typedef enum
{
    MOTOR_IDLE,
    MOTOR_RUN,
    MOTOR_STOP,
    MOTOR_ERROR

} MotorState;

Biến:

MotorState motor_state;

Ban đầu:

motor_state = MOTOR_IDLE;

12. IDLE

case MOTOR_IDLE:

    if(start == 1)
    {
        motor_state = MOTOR_RUN;
    }

    break;

13. RUN

case MOTOR_RUN:

    step_motor_run();

    if(stop == 1)
    {
        motor_state = MOTOR_STOP;
    }

    break;

14. STOP

case MOTOR_STOP:

    step_motor_stop();

    if(start == 1)
    {
        motor_state = MOTOR_RUN;
    }

    break;

15. ERROR

case MOTOR_ERROR:

    step_motor_stop();

    LED_ON();

    if(reset == 1)
    {
        motor_state = MOTOR_IDLE;
    }

    break;

Bây giờ chương trình có cấu trúc rất rõ:

             ┌──────────┐
       ┌────►│   IDLE   │
       │     └────┬─────┘
       │          │ START
       │          ▼
       │     ┌──────────┐
       │     │   RUN    │
       │     └────┬─────┘
       │          │ STOP
       │          ▼
       │     ┌──────────┐
       └─────│   STOP   │
             └──────────┘

                    ERROR
                      ▲
                      │
                 phát hiện lỗi

16. Một điều rất quan trọng: State khác Output

Đây là lỗi người mới rất hay mắc.

Ví dụ:

motor_state = MOTOR_RUN;

Không có nghĩa trực tiếp rằng motor đã quay.

Nó chỉ nói:

“Bộ điều khiển đang ở trạng thái RUN.”

Sau đó State Machine quyết định:

case MOTOR_RUN:
    step_motor_run();
    break;

Cho nên:

STATE
 ↓
LOGIC
 ↓
OUTPUT

Đây là tư duy rất quan trọng.


17. Không nên viết kiểu này

Người mới thường viết:

if(button)
{
    motor = 1;
}

if(sensor)
{
    motor = 0;
}

if(timer)
{
    motor = 1;
}

if(error)
{
    motor = 0;
}

Khi chương trình lớn lên, bạn sẽ không biết:

Tại sao motor đang chạy?

Hoặc:

Điều kiện nào vừa tắt motor?

Đây là kiểu logic rải rác.


18. State Machine giúp giải quyết vấn đề đó

Thay vì:

if(...)
{
   ...
}

if(...)
{
   ...
}

if(...)
{
   ...
}

ta tổ chức:

switch(state)
{
    case IDLE:
        ...
        break;

    case RUN:
        ...
        break;

    case STOP:
        ...
        break;

    case ERROR:
        ...
        break;
}

Mỗi trạng thái có nhiệm vụ riêng.


19. State Machine + Function

Khi chương trình lớn hơn, ta không nên nhét tất cả vào main().

Ví dụ:

void Motor_Task(void)
{
    switch(motor_state)
    {
        case MOTOR_IDLE:

            break;

        case MOTOR_RUN:

            step_motor_run();

            break;

        case MOTOR_STOP:

            step_motor_stop();

            break;

        case MOTOR_ERROR:

            step_motor_stop();

            break;
    }
}

Trong while(1):

while(1)
{
    Motor_Task();
}

Đây là bước rất quan trọng.


20. Nhiều State Machine cùng chạy

Một firmware STM32 thực tế có thể có:

main()
 │
 ├── Button_Task()
 │
 ├── Motor_Task()
 │
 ├── Sensor_Task()
 │
 ├── Display_Task()
 │
 ├── Communication_Task()
 │
 └── Alarm_Task()

Ví dụ:

while(1)
{
    Button_Task();

    Motor_Task();

    Sensor_Task();

    Display_Task();

    Communication_Task();
}

Đây là tư duy cooperative multitasking rất phổ biến trong firmware nhỏ.

Chưa cần RTOS vẫn có thể làm được rất nhiều thứ.


21. Một ví dụ cực thực tế: máy giặt

Ta có:

typedef enum
{
    IDLE,
    FILL,
    WASH,
    DRAIN,
    RINSE,
    SPIN,
    FINISH,
    ERROR

} WashState;

Luồng hoạt động:

          START
            ↓
          IDLE
            ↓
           FILL
            ↓
           WASH
            ↓
          DRAIN
            ↓
          RINSE
            ↓
           SPIN
            ↓
          FINISH
            │
            └──────→ IDLE

Nếu bất cứ lúc nào phát hiện lỗi:

ANY STATE
    │
    │ ERROR
    ▼
  ERROR

Đây chính là cách tư duy để xây dựng firmware máy giặt.


22. State Machine không chỉ dành cho máy móc

Bạn có thể sử dụng nó cho:

Giao tiếp UART

WAIT_START
     ↓
RECEIVE
     ↓
CHECK
     ↓
PROCESS
     ↓
SEND

Menu LCD

MAIN_MENU
    ↓
SETTING
    ↓
EDIT
    ↓
SAVE

Fingerprint

IDLE
 ↓
WAIT_FINGER
 ↓
CAPTURE
 ↓
SEARCH
 ↓
MATCH / FAIL
 ↓
UNLOCK

Robot

IDLE
 ↓
FORWARD
 ↓
OBSTACLE
 ↓
TURN
 ↓
FORWARD

23. Một khái niệm cực kỳ quan trọng: Event

State Machine thường phản ứng với event.

Ví dụ:

BUTTON_START
TIMER_DONE
SENSOR_HIGH
UART_RECEIVED
ERROR_DETECTED

Ví dụ:

if(button_start)
{
    state = RUN;
}

Ở đây:

BUTTON_START = EVENT
RUN          = STATE

Bạn cần bắt đầu phân biệt hai khái niệm này.


24. Công thức tư duy

Hãy nhớ:

STATE + EVENT
       ↓
   TRANSITION
       ↓
NEW STATE

Ví dụ:

IDLE + START
     ↓
    RUN

hoặc:

RUN + ERROR
    ↓
   ERROR

25. Bài tập thực hành Bài 11

Hãy tự viết State Machine cho công tắc vân tay mà bạn đang muốn làm với Blue Pill + DY50.

Thiết kế:

IDLE
WAIT_FINGER
READ_FINGER
CHECK_FINGER
ACCESS_GRANTED
ACCESS_DENIED

Luồng:

IDLE
  ↓
WAIT_FINGER
  ↓
Có ngón tay
  ↓
READ_FINGER
  ↓
CHECK_FINGER
  ├──────────────┐
  │              │
  ▼              ▼
MATCH           FAIL
  │              │
  ▼              ▼
GRANTED         DENIED

Bạn hãy thử tự viết:

typedef enum
{
    IDLE,
    WAIT_FINGER,
    READ_FINGER,
    CHECK_FINGER,
    ACCESS_GRANTED,
    ACCESS_DENIED

} FingerState;

Sau đó:

FingerState state;

và:

switch(state)
{
    ...
}

Đừng cố viết toàn bộ chương trình DY50 ngay. Mục tiêu của bài 11 là bạn phải hiểu được State Machine hoạt động như thế nào.


26. Bạn cần thuộc 5 dòng này

Nếu sau bài này bạn nhớ được 5 dòng sau thì đã đạt mục tiêu:

typedef enum
{
    IDLE,
    RUN,
    ERROR
} State;
State state = IDLE;
switch(state)
{
case RUN:
state = ERROR;

Từ đây, chúng ta đã đi từ:

biến → con trỏ → mảng → struct → hàm → enum → State Machine.

Bài 12

Bài tiếp theo chúng ta sẽ học static, biến cục bộ, biến toàn cục và vùng nhớ của chúng trong STM32. Đây là phần rất quan trọng để bạn hiểu tại sao một biến trong firmware có thể nhớ giá trị sau khi hàm kết thúc, và tại sao cách khai báo biến lại ảnh hưởng đến RAM của Blue Pill.

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Recent Posts

  • Bạn có thể hướng dẫn tôi quy trình sửa chữa một mainboard laptop cũng như mainboard của máy tính để bàn không?
  • Có những mức nguồn DC nào trên một bo mạch mainboard laptop?Kỹ thuật đốt dòng để kiểm tra nguồn laptop được thực hiện như thế nào?
  • bài tiếp theo hợp lý là: BÀI 63 – SENSOR FUSION THỰC CHIẾN: ENCODER + IMU MPU6050 + EKF + ODOMETRY X,Y,θ TRÊN STM32F103
  • BÀI 62 – EKF (EXTENDED KALMAN FILTER) CHO ROBOT 2 BÁNH: FUSION ENCODER + IMU + ƯỚC LƯỢNG X, Y, θ, V, ω
  • BÀI 61 – KALMAN FILTER CHO ENCODER + IMU: ƯỚC LƯỢNG TỐC ĐỘ, GÓC θ VÀ SENSOR FUSION

Recent Comments

No comments to show.

Archives

  • September 2026
  • August 2026
  • July 2026
  • June 2026
  • May 2026
  • February 2026

Categories

  • Altium Desinger
  • Công nghệ
  • ESP32
  • Khác
  • Kiến thức điện máy
  • STM32
Live 3D Globes Visitor
©2026 Công nghệ 9 giây | Design: Newspaperly WordPress Theme