Công nghệ

Tôi thấy hầu hết các thiết bị điện tử đều có thông báo lỗi hiển thị trên màn hình hoặc trên các led ( chẳng hạn lỗi E0,E1,E2…..En).Tôi thấy cách hiển thị ra các lỗi trên rất nhiều sản phẩm như bếp từ,điều hoà,máy làm sữa hạt….tivi,lò vi sóng,quạt điều hoà….Vậy cơ chế thông báo lỗi của các thiết bị hay sản phẩm đó là gì vậy bạn?

Written by lbtmicr06

Đúng rồi. Bạn đang nhìn thấy một mẫu kiến trúc firmware rất phổ biến trong thiết bị điện tử: Fault Detection → Fault Code → Fault Manager → Display/UI.

Điểm quan trọng là: E0, E1, E2… không phải do màn hình tự “phát hiện lỗi”. Chính MCU/firmware phát hiện điều kiện bất thường, gán cho nó một mã lỗi, rồi yêu cầu mạch hiển thị đưa mã đó ra người dùng.


1. Cơ chế tổng quát

Hãy hình dung:

       CẢM BIẾN / PHẦN CỨNG
              │
              ▼
        ┌─────────────┐
        │     MCU     │
        │             │
        │ đọc sensor  │
        └──────┬──────┘
               │
               ▼
        ┌─────────────┐
        │Fault Detect │
        │             │
        │ Có bất thường?│
        └──────┬──────┘
               │
              YES
               │
               ▼
        ┌─────────────┐
        │Fault Manager│
        └──────┬──────┘
               │
          Fault Code
            = E1
               │
       ┌───────┴────────┐
       ▼                ▼
   Display            Buzzer
   "E1"              Beep...

Ví dụ bếp từ:

NTC
 │
 ▼
ADC
 │
 ▼
MCU
 │
 ▼
Temperature > limit ?
 │
 YES
 │
 ▼
FAULT_OVER_TEMP
 │
 ▼
Error Code = E3
 │
 ├────► LED/LCD hiển thị E3
 │
 └────► Tắt công suất

Một mã lỗi thường không chỉ để “báo cho người dùng”. Nó còn là kết quả của một quy trình xử lý an toàn.


2. Ví dụ cực kỳ đơn giản

Giả sử nhà sản xuất quy định:

E0 = không có nồi
E1 = cảm biến nhiệt lỗi
E2 = quá nhiệt
E3 = quá dòng
E4 = lỗi điện áp

Firmware có thể có:

typedef enum
{
    FAULT_NONE = 0,
    FAULT_NO_PAN,
    FAULT_SENSOR,
    FAULT_OVER_TEMP,
    FAULT_OVER_CURRENT,
    FAULT_OVER_VOLTAGE
} FaultCode_t;

Sau đó:

FaultCode_t fault = FAULT_NONE;

3. Firmware kiểm tra lỗi

Ví dụ:

void Safety_Check(void)
{
    if (sensor.temperature > MAX_TEMP)
    {
        fault = FAULT_OVER_TEMP;
    }

    if (sensor.current > MAX_CURRENT)
    {
        fault = FAULT_OVER_CURRENT;
    }

    if (sensor.ntc_fault)
    {
        fault = FAULT_SENSOR;
    }
}

Nhưng đến đây chưa phải toàn bộ cơ chế.

Ta còn cần một tầng:

Fault code nội bộ
       ↓
Fault Manager
       ↓
Xác định mức độ nghiêm trọng
       ↓
Shutdown / Recovery / Display

4. Đây mới là thứ rất giống sản phẩm thương mại

Ví dụ:

FAULT_OVER_TEMP
        │
        ▼
   Fault Manager
        │
        ├── Disable Heater
        │
        ├── Stop PWM
        │
        ├── Start Cooling
        │
        ├── Save fault
        │
        └── Display E2

Vậy nên khi bạn thấy:

E2

thì phía sau nó có thể đã xảy ra cả một chuỗi xử lý.


5. Tại sao nhà sản xuất lại dùng E0, E1, E2?

Bởi vì MCU không cần lưu một chuỗi dài như:

"OVER TEMPERATURE OF INDUCTION COIL"

Nó chỉ cần:

FAULT_OVER_TEMP

và tầng hiển thị chuyển nó thành:

E2

Điều này tiết kiệm bộ nhớ và làm firmware dễ quản lý hơn.


6. Một cách thiết kế tốt hơn

Ta có thể tách thành 3 tầng:

             SENSOR
                │
                ▼
        ┌──────────────┐
        │ Fault Detect │
        └──────┬───────┘
               │
               ▼
        FAULT INTERNAL
               │
               ▼
        ┌──────────────┐
        │Fault Manager │
        └──────┬───────┘
               │
               ▼
          ERROR CODE
               │
               ▼
        ┌──────────────┐
        │  UI Manager  │
        └──────┬───────┘
               │
          ┌────┴────┐
          ▼         ▼
       Display    Buzzer

Ví dụ:

FAULT_OVER_TEMP
       ↓
     code 3
       ↓
      "E2"

7. Nhưng một thiết bị có thể có hàng chục lỗi

Ví dụ điều hòa:

E1 → sensor lỗi
E2 → sensor lỗi
E3 → communication fault
E4 → over temperature
E5 → fan fault
E6 → inverter fault
...

Bếp từ:

E0 → no pan
E1 → sensor
E2 → over temperature
E3 → over current
E4 → voltage
...

Máy giặt:

E01 → door
E02 → water inlet
E03 → drain
E04 → motor
...

Lưu ý: ý nghĩa cụ thể của E0/E1/E2 không có chuẩn chung cho mọi hãng. E1 của một hãng có thể hoàn toàn khác E1 của hãng khác.


8. Điều thú vị là lỗi thường được chia thành nhiều loại

Không phải lỗi nào cũng:

FAULT → OFF ngay

Có thể chia:

Critical

Over current
Short circuit
Severe over temperature

→ tắt công suất ngay.

Serious

Sensor failure
Fan failure

→ dừng chức năng liên quan.

Warning

Filter dirty
Low water

→ vẫn có thể cho thiết bị hoạt động hạn chế.

Informational

No pan
Door open

→ chỉ thông báo.


9. Ví dụ bếp từ: “không có nồi”

Giả sử:

User → Power ON

MCU bắt đầu:

PAN_DETECTION

Nếu không phát hiện nồi:

PAN = FALSE

Firmware:

if (!pan_detected)
{
    fault = FAULT_NO_PAN;
}

Sau đó:

FAULT_NO_PAN
      ↓
Display E0
      ↓
IGBT OFF

Nhưng đây có thể không được coi là một lỗi nghiêm trọng.

Nó có thể là một trạng thái:

WAIT_FOR_PAN

Đây là một điểm rất quan trọng:

Không phải tất cả những gì hiển thị bằng E đều có nghĩa là hệ thống đã hỏng.


10. Ví dụ cảm biến bị đứt

Giả sử NTC được nối vào ADC.

Bình thường:

ADC = 1800

Nhưng dây NTC bị đứt:

ADC = 4095

Firmware có thể:

if (adc_ntc > NTC_OPEN_THRESHOLD)
{
    fault = FAULT_NTC_OPEN;
}

Sau đó:

NTC OPEN
   ↓
FAULT_NTC_OPEN
   ↓
E1
   ↓
HEATER OFF

11. Còn nếu NTC bị chập?

Ví dụ:

ADC ≈ 0

Firmware:

if (adc_ntc < NTC_SHORT_THRESHOLD)
{
    fault = FAULT_NTC_SHORT;
}

→ một lỗi khác.

Vì vậy một cảm biến có thể tạo ra:

E1 = NTC open

E2 = NTC short

hoặc tùy thiết kế.


12. Lỗi còn có thể được phát hiện bằng “timeout”

Đây là cơ chế bạn sẽ gặp rất nhiều trong firmware.

Ví dụ hai MCU giao tiếp UART:

MCU A ───────── UART ───────► MCU B

A gửi:

PING

B phải trả lời:

ACK

Firmware:

PING
 ↓
Start timer
 ↓
Wait ACK
 ↓
ACK received?

Nếu:

100 ms
200 ms
500 ms

vẫn không có ACK:

COMMUNICATION_TIMEOUT

→ Error code.

Đây chính là lý do trong nhiều thiết bị bạn thấy lỗi kiểu:

Communication Error

13. Có một cơ chế còn quan trọng hơn: lỗi phải được “lọc”

Không phải cứ:

Temperature > limit

một lần là lập tức báo lỗi.

Sensor có thể nhiễu.

Ví dụ:

99.8
100.1
99.9
100.2
99.7

Nếu ngưỡng là 100°C mà báo lỗi ngay thì firmware sẽ báo lỗi liên tục.

Thay vào đó:

Temperature > 100°C
        ↓
Start fault timer
        ↓
Vẫn > 100°C?
        ↓
200 ms?
        ↓
500 ms?
        ↓
YES
        ↓
FAULT

Đây gọi là debounce / filtering / persistence time tùy ngữ cảnh.


14. Có thể dùng counter

Ví dụ:

if (temperature > MAX_TEMP)
{
    over_temp_counter++;

    if (over_temp_counter >= 10)
    {
        fault = FAULT_OVER_TEMP;
    }
}
else
{
    over_temp_counter = 0;
}

Nếu task chạy mỗi 100 ms:

10 lần × 100 ms = 1 giây

→ nhiệt độ phải vượt ngưỡng liên tục 1 giây mới báo lỗi.


15. Nhưng lỗi quá dòng có thể khác hoàn toàn

Đối với một sự kiện nguy hiểm:

SHORT CIRCUIT

không thể chờ:

1 giây

mà phải:

Current abnormal
       ↓
Hardware protection
       ↓
Gate OFF

sau đó MCU mới xử lý:

Fault interrupt
       ↓
FAULT_OVERCURRENT
       ↓
Display E3

Đây chính là sự khác biệt giữa:

Fast protection

Software diagnosis.


16. Một kiến trúc Fault Manager hoàn chỉnh

Tôi sẽ thiết kế như sau:

                    SENSOR
                      │
       ┌──────────────┼───────────────┐
       ▼              ▼               ▼
   Temperature      Current         Voltage
       │              │               │
       └──────────────┼───────────────┘
                      ▼
                FAULT DETECTOR
                      │
              ┌───────┴────────┐
              ▼                ▼
          Warning           Critical
              │                │
              ▼                ▼
         Fault Manager    Emergency Stop
              │                │
              └───────┬────────┘
                      ▼
                 Fault Database
                      │
              ┌───────┼─────────┐
              ▼       ▼         ▼
            Code    Action     UI
              │       │         │
              ▼       ▼         ▼
             E2    Heater OFF  Display

17. Fault Database rất thú vị

Thay vì viết hàng trăm if, ta có thể định nghĩa:

typedef struct
{
    FaultCode_t code;
    uint8_t critical;
    uint8_t shutdown;
    uint16_t display_code;
} FaultInfo_t;

Ví dụ:

const FaultInfo_t fault_table[] =
{
    {FAULT_NO_PAN,       0, 0, 0},
    {FAULT_NTC_OPEN,     1, 1, 1},
    {FAULT_OVER_TEMP,   1, 1, 2},
    {FAULT_OVER_CURRENT, 1, 1, 3},
    {FAULT_OVER_VOLTAGE, 1, 1, 4}
};

Sau đó:

FAULT_OVER_TEMP
      ↓
lookup table
      ↓
critical = YES
shutdown = YES
display = E2

Đây là cách thiết kế rất dễ mở rộng.


18. Và mã lỗi có thể được lưu vào Flash

Đây là một tính năng rất hay trong sản phẩm thực tế.

Ví dụ:

Thiết bị
  ↓
Over-current
  ↓
E3

MCU có thể lưu:

Last Fault = E3
Fault Counter = 17

vào Flash/EEPROM.

Sau khi người dùng tắt nguồn:

POWER OFF

rồi bật lại:

POWER ON

firmware vẫn có thể biết:

Previous fault = E3

Kỹ thuật viên bảo hành có thể đọc lịch sử lỗi.


19. Vì vậy một mã E3 bạn nhìn thấy trên màn hình thực ra chỉ là “đỉnh của tảng băng”

Ví dụ bạn thấy:

             E3

Nhưng bên trong:

Current sensor
      ↓
ADC
      ↓
Filtering
      ↓
Current calculation
      ↓
Threshold comparison
      ↓
Fault persistence
      ↓
Fault Manager
      ↓
FAULT_OVER_CURRENT
      ↓
Emergency shutdown
      ↓
Save fault
      ↓
Display Manager
      ↓
SEGMENT "E"
      ↓
SEGMENT "3"
      ↓
LED/LCD

Đó mới là toàn bộ cơ chế.


20. Và điều này liên hệ trực tiếp với STM32 mà bạn đang học

Bạn đã học:

GPIO
Timer
ADC
UART
Interrupt
DMA

Bây giờ chúng ta có thể ghép chúng lại:

                 STM32
                   │
      ┌────────────┼────────────┐
      │            │            │
     ADC          GPIO        UART
      │            │            │
   Sensor         Key        Debug
      │
      ▼
 Fault Detection
      │
      ▼
 Fault Manager
      │
      ▼
 State Machine
      │
      ├────────► Control
      │
      └────────► Display

Và đây chính là lúc các kiến thức rời rạc bắt đầu trở thành một firmware hoàn chỉnh.


Một điểm cuối cùng rất đáng nhớ

Khi học firmware, bạn có thể coi toàn bộ hệ thống lỗi theo công thức:

Detect → Validate → Classify → Protect → Record → Display → Recover

Ví dụ bếp từ:

Dòng điện quá lớn
      ↓
DETECT
      ↓
VALIDATE
      ↓
CLASSIFY = OVER CURRENT
      ↓
PROTECT = IGBT OFF
      ↓
RECORD = Fault E3
      ↓
DISPLAY = E3
      ↓
RECOVER hoặc LOCK

đây là một pattern có thể áp dụng cho bếp từ, nồi cơm, điều hòa, máy giặt, lò vi sóng, máy làm sữa hạt, quạt điều hòa… gần như mọi thiết bị nhúng có chẩn đoán lỗi.

Nếu tiếp tục dự án STM32F103 của chúng ta, bước rất đáng làm tiếp theo là tự xây một “Fault Manager” hoàn chỉnh: tạo khoảng 10 lỗi giả lập (E0–E9), dùng ADC để giả lập sensor, Timer để tạo timeout, Interrupt để giả lập lỗi khẩn cấp, rồi để STM32 tự phát hiện → khóa công suất → hiển thị E-code → ghi lịch sử lỗi → tự recovery. Đây sẽ là một bài tập cực kỳ sát với firmware sản phẩm thực tế.

About the author

lbtmicr06

Leave a Comment