/** * main.c — OOPC 不透明指针模式完整演示 * * 功能: * 1. 创建 2 个 LED 对象(状态灯、告警灯) * 2. 创建 1 个按键对象,按键单击/双击控制 LED 切换 * 3. 演示 OOPC 的"编译期数据封装":如果你尝试访问 * 内部结构体成员,编译器会报错 * * 构建:make all * 烧录:用 ST-Link 烧录 led_oopc_demo.bin 到 STM32F103 开发板 */ #include /* NULL */ #include "led.h" #include "button.h" /* ======================================================== * 全局句柄——通过 OOPC 创建的组件实例 * 外部代码只能持有指针,无法访问内部字段 * ======================================================== */ static Led_S* g_led_status; /* 状态指示灯 (PB12) */ static Led_S* g_led_alarm; /* 告警灯 (PB13) */ static Button_S* g_btn_user; /* 用户按键 (PA0, 低电平有效) */ /* ======================================================== * 按键事件回调 * ======================================================== */ static void on_button_event(Button_Event evt, void* context) { (void)context; /* 本例未使用 context */ switch (evt) { case BTN_EVT_CLICK: /* 单击:切换状态灯 */ Led_Toggle(g_led_status); break; case BTN_EVT_DBL_CLICK: /* 双击:切换告警灯 */ Led_Toggle(g_led_alarm); break; case BTN_EVT_PRESSED: /* 按下:点亮所有灯(演示同时控制多个实例) */ Led_On(g_led_status); Led_On(g_led_alarm); break; case BTN_EVT_RELEASED: /* 释放:熄灭告警灯,状态灯保留当前状态 */ Led_Off(g_led_alarm); break; default: break; } } /* ======================================================== * 系统延时(简单粗暴的循环延时,仅演示用) * ======================================================== */ static void delay_loop(volatile uint32_t count) { while (count--) { __NOP(); } } /* ======================================================== * main * ======================================================== */ int main(void) { /* ── 第一步:创建 OOPC 组件实例 ── */ /* LED 组件 */ g_led_status = Led_Create(GPIOB, 12); /* PB12 */ g_led_alarm = Led_Create(GPIOB, 13); /* PB13 */ /* 按键组件 */ ButtonConfig btn_cfg; btn_cfg.gpio_port = 0; /* 端口 A */ btn_cfg.gpio_pin = 0; /* pin 0 */ btn_cfg.active_low = 1; /* 低电平=按下 */ btn_cfg.callback = on_button_event; btn_cfg.context = NULL; g_btn_user = Button_Create(&btn_cfg); /* 创建失败检查 */ if (g_led_status == NULL || g_led_alarm == NULL || g_btn_user == NULL) { /* 在实际工程中应该做错误处理 */ while (1); /* 挂起 */ } /* ── 第二步:演示 OOPC 编译期保护 ── */ /* * 下面的每一行如果取消注释,编译器都会报错: * * error: dereferencing pointer to incomplete type 'struct Led_S' * * 原因:Led_S 的完整定义在 led.c 中,外部不可见。 * main.c 只知道它是一种类型,但不知道它有哪些字段。 */ // g_led_status->port = GPIOB; /* 编译错误! */ // g_led_status->pin = GPIO_Pin_12; /* 编译错误! */ // g_led_status->state = 1; /* 编译错误! */ // g_btn_user->fsm_state = 0; /* 编译错误! */ /* * OOPC 强制所有操作走 API: * Led_On(), Led_Off(), Button_Poll(), Button_IsPressed() ... * * 这就保证了: * 1. 数据私有——无法越权修改内部状态 * 2. 接口统一——所有访问都经过函数,方便加断点调试 * 3. 重构自由——修改结构体字段不影响外部代码 */ /* ── 第三步:主循环 ── */ /* 开机闪烁 3 次,确认 LED 工作正常 */ for (uint8_t i = 0; i < 3; i++) { Led_On(g_led_status); delay_loop(2000000); Led_Off(g_led_status); Led_On(g_led_alarm); delay_loop(2000000); Led_Off(g_led_alarm); } while (1) { /* 轮询按键 FSM(内部处理去抖动和单/双击判断) */ Button_Poll(g_btn_user); /* 简单延时,给 CPU 喘息时间 */ delay_loop(500000); } }