【0基础嵌入式学习日志】Day09:枚举 enum、系统工作模式与 switch-case 状态打印

【0基础嵌入式学习日志】Day09:枚举 enum、系统工作模式与 switch-case 状态打印

一、前言

今天继续进行嵌入式 C 语言基础学习。

前面几天已经学习了 C 工程结构、多文件拆分、Makefile 自动化编译、头文件依赖追踪、DEBUG 调试日志以及 config.h 参数集中管理。

Day01:基础 C 工程结构
Day02:函数封装、结构体指针、故障判断
Day03:多文件拆分,.h / .c 配合
Day04:.c → .o → 可执行文件
Day05:Makefile 自动化、模式规则、增量编译
Day06:.d 依赖文件,头文件依赖追踪
Day07:条件编译、DEBUG 开关与日志打印模块
Day08:config.h 配置头文件、阈值宏管理与消除魔法数字

Day09 的重点是学习 枚举 enum,并给系统增加一个新的状态字段:

SystemMode mode;

这个字段用于表示系统当前处于哪种工作模式,例如:

初始化模式
正常运行模式
故障模式

在嵌入式项目中,系统状态管理非常常见。比如一个设备可能处于初始化、运行、待机、故障、低功耗等不同状态。相比直接使用 012 这样的数字,用 enum 可以让代码更加清晰。


二、Day09 学习目标

本次 Day09 主要学习以下内容:

  1. 理解 enum 枚举的基本作用;
  2. 学会用枚举表示系统固定状态;
  3. SystemStatus 结构体中新增系统工作模式字段;
  4. 在系统初始化时设置默认模式;
  5. 根据故障码切换 RUNFAULT 模式;
  6. 使用 switch-case 打印不同系统模式;
  7. 验证 FAULTRUN 两种状态是否正确切换。

三、Day09 工程结构

Day09 是在 Day08 基础上继续修改得到的。

工程结构如下:

day09
├── Makefile
├── include
│   ├── config.h
│   ├── debug.h
│   ├── fault_code.h
│   ├── fault.h
│   ├── sensor.h
│   ├── system.h
│   └── system_type.h
├── src
│   ├── fault.c
│   ├── main.c
│   ├── sensor.c
│   └── system.c
└── build
    └── day09_test

其中:

  • system_type.h:定义系统状态结构体和系统模式枚举;
  • system.c:系统初始化和状态打印;
  • fault.c:故障检测和系统模式切换;
  • config.h:保存传感器模拟值和故障阈值;
  • Makefile:自动编译和运行工程。

四、为什么需要 enum?

如果不用枚举,系统模式可能会写成这样:

sys->mode = 0;
sys->mode = 1;
sys->mode = 2;

但是问题是,别人看到 012 时,并不知道它们分别代表什么。

例如:

0 是初始化?
1 是运行?
2 是故障?

这种代码可读性比较差。

使用 enum 后,可以写成:

sys->mode = SYS_MODE_INIT;
sys->mode = SYS_MODE_RUN;
sys->mode = SYS_MODE_FAULT;

这样代码含义就很清楚:

SYS_MODE_INIT   初始化模式
SYS_MODE_RUN    正常运行模式
SYS_MODE_FAULT  故障模式

所以,enum 的作用可以简单理解为:

用有意义的名字表示一组固定状态。

五、定义系统工作模式枚举

day09/include/system_type.h 中新增 SystemMode 枚举类型:

#ifndef SYSTEM_TYPE_H
#define SYSTEM_TYPE_H

typedef enum
{
    SYS_MODE_INIT = 0,
    SYS_MODE_RUN,
    SYS_MODE_FAULT
} SystemMode;

typedef struct
{
    int led_state;
    SystemMode mode;
    float voltage;
    float current;
    float temperature;
    unsigned int fault_code;
} SystemStatus;

#endif

其中:

typedef enum
{
    SYS_MODE_INIT = 0,
    SYS_MODE_RUN,
    SYS_MODE_FAULT
} SystemMode;

定义了一个新的类型:

SystemMode

它包含三个系统模式:

SYS_MODE_INIT   初始化模式
SYS_MODE_RUN    正常运行模式
SYS_MODE_FAULT  故障模式

这里手动给 SYS_MODE_INIT 赋值为 0

SYS_MODE_INIT = 0

后面的枚举值如果没有手动赋值,会自动递增:

SYS_MODE_INIT  = 0
SYS_MODE_RUN   = 1
SYS_MODE_FAULT = 2

虽然它们本质上还是整数,但在代码中使用名字会比直接写数字更清楚。


六、SystemStatus 结构体新增 mode 字段

Day08 的 SystemStatus 结构体中已经有:

int led_state;
float voltage;
float current;
float temperature;
unsigned int fault_code;

这些字段用于保存 LED 状态、电压、电流、温度和故障码。

Day09 新增了一个字段:

SystemMode mode;

完整结构体如下:

typedef struct
{
    int led_state;
    SystemMode mode;
    float voltage;
    float current;
    float temperature;
    unsigned int fault_code;
} SystemStatus;

这个字段的作用是保存当前系统模式。

以后可以通过:

sys->mode = SYS_MODE_INIT;

表示系统处于初始化模式。

也可以通过:

sys->mode = SYS_MODE_FAULT;

表示系统处于故障模式。


七、系统初始化时设置 INIT 模式

day09/src/system.csystem_init() 函数中,需要初始化系统模式。

修改后的代码如下:

void system_init(SystemStatus *sys)
{
    sys->led_state = SYS_INIT_LED_STATE;
    sys->mode = SYS_MODE_INIT;
    sys->voltage = SYS_INIT_VOLTAGE;
    sys->current = SYS_INIT_CURRENT;
    sys->temperature = SYS_INIT_TEMPERATURE;
    sys->fault_code = FAULT_NONE;

    DEBUG_PRINT("system init done\n");
}

新增的是这一句:

sys->mode = SYS_MODE_INIT;

意思是:

系统刚初始化时,默认处于初始化模式。

这里不要直接写:

sys->mode = 0;

虽然 SYS_MODE_INIT 的值就是 0,但是写成 SYS_MODE_INIT 更容易理解。


八、根据故障码切换系统模式

系统初始化后,传感器数据会更新,然后进入故障检测。

day09/src/fault.c 中,根据 fault_code 判断系统是正常运行还是故障状态:

void fault_check(SystemStatus *sys)
{
    sys->fault_code = FAULT_NONE;

    if(sys->voltage < FAULT_LOW_VOLTAGE_TH)
    {
        sys->fault_code |= FAULT_LOW_VOLTAGE;
    }

    if(sys->current > FAULT_OVER_CURRENT_TH)
    {
        sys->fault_code |= FAULT_OVER_CURRENT;
    }

    if(sys->temperature > FAULT_OVER_TEMP_TH)
    {
        sys->fault_code |= FAULT_OVER_TEMP;
    }

    if(sys->fault_code == FAULT_NONE)
    {
        sys->mode = SYS_MODE_RUN;
    }
    else
    {
        sys->mode = SYS_MODE_FAULT;
    }

    DEBUG_PRINT("fault check done\n");
}

核心新增代码是:

if(sys->fault_code == FAULT_NONE)
{
    sys->mode = SYS_MODE_RUN;
}
else
{
    sys->mode = SYS_MODE_FAULT;
}

意思是:

如果 fault_code 等于 FAULT_NONE,说明没有故障,系统模式为 RUN;
如果 fault_code 不等于 FAULT_NONE,说明存在故障,系统模式为 FAULT。

这样系统模式就和故障检测结果关联起来了。


九、使用 switch-case 打印系统模式

system_print() 中,使用 switch-case 根据 sys->mode 打印系统模式。

void system_print(const SystemStatus *sys)
{
    printf("LED state: %d\n", sys->led_state);

    switch(sys->mode)
    {
        case SYS_MODE_INIT:
            printf("System mode: INIT\n");
            break;

        case SYS_MODE_RUN:
            printf("System mode: RUN\n");
            break;

        case SYS_MODE_FAULT:
            printf("System mode: FAULT\n");
            break;

        default:
            printf("System mode: UNKNOWN\n");
            break;
    }

    printf("Voltage: %.2f V\n", sys->voltage);
    printf("Current: %.2f A\n", sys->current);
    printf("temperature: %.2f C\n", sys->temperature);
    printf("Fault code: 0x%04X\n", sys->fault_code);

    if(sys->fault_code & FAULT_LOW_VOLTAGE)
    {
        printf("Fault: Low voltage\n");
    }

    if(sys->fault_code & FAULT_OVER_CURRENT)
    {
        printf("Fault: Over current\n");
    }

    if(sys->fault_code & FAULT_OVER_TEMP)
    {
        printf("Fault: Over temperature\n");
    }

    if(sys->fault_code == FAULT_NONE)
    {
        printf("System normal\n");
    }
}

其中:

switch(sys->mode)

表示根据 sys->mode 的值进入不同分支。

例如:

case SYS_MODE_FAULT:
    printf("System mode: FAULT\n");
    break;

表示如果当前系统模式是 SYS_MODE_FAULT,就打印:

System mode: FAULT

break 的作用是结束当前分支,跳出 switch

如果没有 break,程序可能会继续执行后面的 case,导致输出混乱。


十、为什么这里用 switch-case?

当然,也可以用 if-else 实现:

if(sys->mode == SYS_MODE_INIT)
{
    printf("System mode: INIT\n");
}
else if(sys->mode == SYS_MODE_RUN)
{
    printf("System mode: RUN\n");
}
else if(sys->mode == SYS_MODE_FAULT)
{
    printf("System mode: FAULT\n");
}
else
{
    printf("System mode: UNKNOWN\n");
}

但是像系统模式这种“一个变量对应多个固定状态”的情况,用 switch-case 更清晰。

所以可以简单记忆:

状态分支多,适合 switch-case;
普通条件判断,适合 if-else。

十一、Makefile 修改

因为 Day09 是从 Day08 复制过来的,所以需要将目标文件名改成 Day09 对应名称。

TARGET = build/day09_test

完整 Makefile 主要内容如下:

CC = gcc
CFLAGS = -Wall -Wextra -Iinclude
DEPFLAGS = -MMD -MP
DEBUG ?= 1

ifeq ($(DEBUG),1)
CFLAGS += -DDEBUG
endif

TARGET = build/day09_test

SRCS = $(wildcard src/*.c)
OBJS = $(patsubst src/%.c, build/%.o, $(SRCS))
DEPS = $(patsubst src/%.c, build/%.d, $(SRCS))

all: $(TARGET)

$(TARGET): $(OBJS)
	$(CC) $(OBJS) -o $(TARGET)

build/%.o: src/%.c
	$(CC) $(CFLAGS) $(DEPFLAGS) -c $< -o $@

run: $(TARGET)
	./$(TARGET)

clean:
	rm -f build/*.o build/*.d $(TARGET)

-include $(DEPS)

这样最终生成的可执行文件就是:

build/day09_test

十二、FAULT 模式测试

默认情况下,config.h 中的传感器模拟值如下:

#define SENSOR_SIM_VOLTAGE        9.5f
#define SENSOR_SIM_CURRENT        2.5f
#define SENSOR_SIM_TEMPERATURE    75.0f

故障判断阈值为:

#define FAULT_LOW_VOLTAGE_TH      10.0f
#define FAULT_OVER_CURRENT_TH     2.0f
#define FAULT_OVER_TEMP_TH        60.0f

由于:

9.5 < 10.0
2.5 > 2.0
75.0 > 60.0

所以会同时触发低电压、过电流和过温故障。

执行:

cd /root/Embedded_14Days/day09
make clean
make
make run

运行结果:

[DEBUG] system init done
[DEBUG] sensor update done
[DEBUG] fault check done
LED state: 0
System mode: FAULT
Voltage: 9.50 V
Current: 2.50 A
temperature: 75.00 C
Fault code: 0x0007
Fault: Low voltage
Fault: Over current
Fault: Over temperature

可以看到:

System mode: FAULT

说明存在故障时,系统模式能够正确切换为故障模式。


十三、RUN 模式测试

为了验证正常运行模式,将 config.h 中的传感器模拟值临时改成正常范围:

#define SENSOR_SIM_VOLTAGE        12.0f
#define SENSOR_SIM_CURRENT        1.0f
#define SENSOR_SIM_TEMPERATURE    35.0f

重新执行:

make clean
make
make run

运行结果变为:

[DEBUG] system init done
[DEBUG] sensor update done
[DEBUG] fault check done
LED state: 0
System mode: RUN
Voltage: 12.00 V
Current: 1.00 A
temperature: 35.00 C
Fault code: 0x0000
System normal

可以看到:

System mode: RUN
Fault code: 0x0000
System normal

说明没有故障时,系统模式能够正确切换为正常运行模式。

验证完成后,将 config.h 恢复为默认故障模拟值:

#define SENSOR_SIM_VOLTAGE        9.5f
#define SENSOR_SIM_CURRENT        2.5f
#define SENSOR_SIM_TEMPERATURE    75.0f

十四、今天遇到的问题

1. enum 写法错误

一开始把 enum 写成了类似:

typedef enum
[
    SYS_MODE_INIT = 0,
    SYS_MODE_RUN,
    SYS_MODE_FAULT
] SystemMode;

这是错误的,因为 C 语言中的 enum 要使用大括号 {},不能使用中括号 []

正确写法是:

typedef enum
{
    SYS_MODE_INIT = 0,
    SYS_MODE_RUN,
    SYS_MODE_FAULT
} SystemMode;

2. 结构体字段拼写错误

一开始把:

SystemMode mode;

误写成了类似:

SystemMode maode;

这样后面如果写:

sys->mode = SYS_MODE_INIT;

就会报错,因为结构体里并没有 mode 这个成员。

所以变量名必须前后一致。


3. 把 C 代码误输入到终端

在修改 system.c 时,曾经把:

sys->mode = SYS_MODE_INIT;

误输入到了终端里。

终端报错:

Command 'sys-' not found

这是因为终端是执行 Linux 命令的地方,不是写 C 代码的地方。

代码应该写在 .c 文件里,例如:

day09/src/system.c

4. VS Code WSL 卡住问题

今天还遇到了 VS Code 连接 WSL 卡住、扩展导致窗口崩溃的问题。

最后通过以下方式解决:

关闭 VS Code
wsl --shutdown
清理 VS Code Server
禁用部分扩展后重新打开

这个问题和代码本身无关,是 VS Code 与 WSL 连接环境的问题。


十五、今日总结

通过 Day09 的学习,主要掌握了以下内容:

  1. 理解了 enum 枚举的基本作用;
  2. 学会了用枚举表示系统固定状态;
  3. SystemStatus 结构体中新增了 mode 字段;
  4. 学会了在系统初始化时设置默认模式;
  5. 学会了根据故障码切换 RUNFAULT 模式;
  6. 学会了使用 switch-case 打印不同系统模式;
  7. 验证了 FAULTRUN 两种系统模式;
  8. 进一步理解了嵌入式系统中的状态管理思想。

Day09 的核心可以总结为:

enum 用有意义的名字表示固定状态;
switch-case 用于根据状态执行不同分支逻辑。

这一步虽然代码量不大,但非常接近真实嵌入式工程中的状态管理方式。后续学习状态机、任务调度、故障保护和设备运行流程时,都会继续用到类似思想。


十六、项目源码

本次 Day09 学习代码已上传至 GitHub:

https://github.com/jdai10590-afk/Embedded-C-Learning-Projects/tree/main/day09

duhong2026

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值