嵌入式C语言设计模式
1. 什么是设计模式设计模式是对软件设计中反复出现问题的通用解决方案或模板它描述了在特定情境下如何组织类、对象及它们之间的交互从而解决常见的设计问题。设计模式不是可直接拷贝的代码而是一种软件设计思想和可复用的代码结构设计方法。2. 设计模式的核心思想•解耦把硬件驱动和业务逻辑分离降低修改风险与回归成本。•复用把通用功能抽象成可复用模块避免复制粘贴带来的维护负担。•扩展通过接口和工厂等机制新增功能时尽量不改动已有代码减少引入新 bug 的概率。3. 单例模式管好硬件资源特点保证系统中某个对象只有一个实例通常用于管理唯一硬件资源或全局服务。适用场景UART、SPI、I2C、外设控制器、系统日志模块等全局唯一资源。优点避免重复初始化、配置冲突提供统一访问点。注意事项避免把过多业务逻辑塞入单例防止全局状态污染和测试困难。// uart_singleton.c #include stdint.h #include stdio.h typedefstruct { int initialized; uint32_t baudrate; } UART_Handle; UART_Handle* UART_GetInstance(void) { static UART_Handle uart; if (!uart.initialized) { // 实际硬件初始化放在这里 uart.baudrate 115200; uart.initialized 1; printf(UART initialized\n); } return uart; } // 使用示例 UART_Handle* u UART_GetInstance();4. 适配器模式让换芯片不再痛苦• 特点通过定义统一接口屏蔽底层平台差异上层只依赖接口而非具体实现。• 适用场景需要支持多种 MCU、替换 HAL 库、跨平台移植、统一外设操作。• 优点换芯片或替换底层库时只需实现适配层上层业务代码无需修改。• 注意事项接口设计要稳健且尽量覆盖上层需求避免频繁改动接口。// gpio_adapter.h typedefstruct { void (*write)(int pin, int value); int (*read)(int pin); } GPIO_Interface; // stm32_gpio.c #include gpio_adapter.h #include stdio.h void stm32_gpio_write(int pin, int value) { // HAL_GPIO_WritePin(...) printf(STM32 GPIO write pin%d val%d\n, pin, value); } int stm32_gpio_read(int pin) { // return HAL_GPIO_ReadPin(...); return 0; } GPIO_Interface stm32_gpio { .write stm32_gpio_write, .read stm32_gpio_read }; // 上层只依赖 GPIO_Interface不关心底层实现5. 工厂模式优雅地管理多种设备• 特点把对象创建逻辑集中管理返回统一接口的实例避免在业务代码中散布大量 if-else。• 适用场景多种传感器、多种外设驱动、插件式设备扩展。• 优点新增设备只需实现接口并在工厂注册业务代码无需改动。• 注意事项工厂实现要易于扩展注册机制要清晰静态表或注册函数。// sensor.h typedefstruct { void (*init)(void); float (*read)(void); } Sensor; // ds18b20.c #include sensor.h #include stdio.h static void ds18b20_init(void) { printf(DS18B20 init\n); } static float ds18b20_read(void) { return 25.0f; } Sensor DS18B20 { .init ds18b20_init, .read ds18b20_read }; // ntc.c static void ntc_init(void) { printf(NTC init\n); } static float ntc_read(void) { return 30.5f; } Sensor NTC { .init ntc_init, .read ntc_read }; // factory.c #include string.h Sensor* SensorFactory(const char* type) { if (strcmp(type, DS18B20) 0) return DS18B20; if (strcmp(type, NTC) 0) return NTC; return NULL; } // 使用示例 /* Sensor* s SensorFactory(DS18B20); if (s) { s-init(); float t s-read(); } */6. 对象池模式在内存紧张时优雅地活着• 特点预先分配固定数量对象并循环复用避免运行时频繁 malloc/free 导致内存碎片。• 适用场景通信缓冲区、短生命周期对象、任务/消息对象池。• 优点降低内存碎片风险、提高分配效率、可预测内存使用。• 注意事项池大小需根据最大并发需求合理规划要处理池耗尽的情况返回错误或阻塞。// obj_pool.c #include string.h #include stdio.h #define POOL_SIZE 5 typedefstruct { int used; char buf[64]; } Obj; static Obj pool[POOL_SIZE]; Obj* pool_get(void) { for (int i 0; i POOL_SIZE; i) { if (!pool[i].used) { pool[i].used 1; memset(pool[i].buf, 0, sizeof(pool[i].buf)); return pool[i]; } } return NULL; // 池耗尽 } void pool_release(Obj* o) { if (o) o-used 0; } // 使用示例 /* Obj* o pool_get(); if (o) { strcpy(o-buf, data); pool_release(o); } */7. 观察者模式让模块之间不再互相纠缠• 特点事件发布-订阅机制发布者只负责发事件订阅者自行注册处理逻辑实现模块解耦。• 适用场景按键事件、状态变化通知、日志/监控、异步消息分发。• 优点新增响应逻辑无需修改事件源便于扩展和模块化。• 注意事项订阅者过多或处理耗时会影响发布者性能必要时使用任务队列或异步处理。// event_bus.c #include stdio.h #define MAX_OBSERVERS 8 typedef void (*Observer)(void* ctx); static Observer observers[MAX_OBSERVERS]; static void* observer_ctx[MAX_OBSERVERS]; static int obs_count 0; int subscribe(Observer o, void* ctx) { if (obs_count MAX_OBSERVERS) return -1; observers[obs_count] o; observer_ctx[obs_count] ctx; obs_count; return 0; } void notify_all(void) { for (int i 0; i obs_count; i) { if (observers[i]) observers[i](observer_ctx[i]); } } // 示例订阅者 void display_update(void* ctx) { printf(Display update: %s\n, (char*)ctx); } void relay_control(void* ctx) { printf(Relay control: %s\n, (char*)ctx); } // 使用示例 /* subscribe(display_update, Key1); subscribe(relay_control, Key1); // 按键中断或轮询检测到按下时 notify_all(); */实践总结模式适用场景优点注意事项单例模式硬件资源唯一UART\SPI\I2C等避免重复初始化、统一管理避免全局状态过多影响测试适配器模式换芯片、跨平台、硬件抽象上层代码无需修改接口设计要稳定且覆盖需求工厂模式多种传感器/设备管理避免大量的if-else易拓展工厂注册/维护要清晰对象池模式内存紧张、频繁分配释放场景减少碎片、提高效率池大小需合理、处理耗尽对应策略观察者模式事件驱动、按键、消息通知模块解耦、易拓展订阅者过多或耗时处理需异步化常见反模式操作1. 把所有逻辑塞进 main.c问题文件臃肿、可读性差、修改风险高。后果任何小改动都可能牵动全局难以定位 bug。改进按功能拆分模块按层次划分目录driver、hal、service、app。2. 滥用全局变量问题状态不可控、并发/中断下易出错、测试困难。后果难以追踪数据流模块间耦合度高。改进尽量使用局部变量、通过接口传参或单例封装共享资源。3. 频繁在运行时 malloc/free问题内存碎片、不可预测的失败。后果长期运行后系统崩溃或行为异常。改进使用对象池或静态分配避免动态分配在关键路径。4. 硬编码硬件寄存器和魔法数字问题可移植性差、难以维护。后果换芯片或修改引脚时需要大范围改动。改进使用宏、配置表或适配层抽象硬件细节。5. 过度设计或过度抽象问题为小项目引入复杂架构增加理解成本。后果开发效率下降团队成员难以上手。改进按需设计先简单后重构在增长到需要时再引入复杂模式。6. 业务逻辑与驱动混在一起问题换芯片或替换驱动时需要改动业务代码。后果移植成本高回归测试量大。改进严格分层驱动层只做硬件操作上层通过接口调用。总结设计模式的是计算机发展史上无数人总结出的宝贵经验掌握设计模式将使你从纯粹的码农逐渐成长为有全局思维有架构设计能力的程序员架构师。但设计模式不是万能套路在中大型或长期维护的嵌入式项目中它们能显著提升代码的可维护性、可扩展性和可读性在项目初期花一点时间做代码架构设计后续能省下大量返工时间。对于小型项目可能会增加额外的资源消耗需根据实际情况应用写能跑的代码不难写别人能看懂、能维护、能扩展的代码才是真本事。

相关新闻

基于Java的NBA球队管理系统(11885)

基于Java的NBA球队管理系统(11885)

有需要的同学,源代码和配套文档领取,加文章最下方的名片哦 一、项目演示 项目演示视频 二、资料介绍 完整源代码(前后端源代码SQL脚本)配套文档(LWPPT开题报告)远程调试控屏包运行 三、技术介绍 Java…

2026/5/17 6:33:08 阅读更多 →
信管毕设新颖的项目选题建议

信管毕设新颖的项目选题建议

0 选题推荐 - 大数据篇 毕业设计是大家学习生涯的最重要的里程碑,它不仅是对四年所学知识的综合运用,更是展示个人技术能力和创新思维的重要过程。选择一个合适的毕业设计题目至关重要,它应该既能体现你的专业能力,又能满足实际应…

2026/5/17 6:33:07 阅读更多 →
创业团队用 XinServer 实现快速后台运维管理

创业团队用 XinServer 实现快速后台运维管理

创业团队用 XinServer 实现快速后台运维管理 最近跟几个创业的朋友聊天,发现大家有个共同的烦恼:产品想法贼棒,前端页面也做得飞起,但一到后端和服务器这块就卡住了。要么是团队里没人懂后端,要么是后端兄弟忙不过来&a…

2026/7/5 7:35:52 阅读更多 →

最新新闻

Power BI DAX上下文与CALCULATE实战指南

Power BI DAX上下文与CALCULATE实战指南

1. 这不是“又一个DAX教程”——它是一份能让你在真实业务场景里立刻写出有效公式的生存指南Power BI DAX Tutorial for Beginners 这个标题背后藏着的,不是一套PPT式概念罗列,而是一群每天被销售漏斗断层、库存周转失真、客户复购率口径打架折磨得睡不着…

2026/7/6 4:24:19 阅读更多 →
实战指南:HBCTool高效反编译Hermes字节码的完整解决方案

实战指南:HBCTool高效反编译Hermes字节码的完整解决方案

实战指南:HBCTool高效反编译Hermes字节码的完整解决方案 【免费下载链接】hbctool Hermes Bytecode Reverse Engineering Tool (Assemble/Disassemble Hermes Bytecode) 项目地址: https://gitcode.com/gh_mirrors/hb/hbctool HBCTool是一款专为React Native…

2026/7/6 4:24:19 阅读更多 →
方向科技 GEO 优化决策系统新手实战指南

方向科技 GEO 优化决策系统新手实战指南

在当前的数字化营销环境中,许多品牌方和运营团队都面临着一个共同的痛点:传统的获客方式成本越来越高,而转化效率却在不断下降。我们花费大量精力制作内容、投放广告,却往往难以精准触达那些真正有需求的潜在客户。更令人头疼的是…

2026/7/6 4:24:19 阅读更多 →
5分钟掌握AMD Ryzen处理器调试工具:从新手到调优专家

5分钟掌握AMD Ryzen处理器调试工具:从新手到调优专家

5分钟掌握AMD Ryzen处理器调试工具:从新手到调优专家 【免费下载链接】SMUDebugTool A dedicated tool to help write/read various parameters of Ryzen-based systems, such as manual overclock, SMU, PCI, CPUID, MSR and Power Table. 项目地址: https://git…

2026/7/6 4:22:18 阅读更多 →
LTC6904与PIC24FV16KA304实现精密脉冲控制方案

LTC6904与PIC24FV16KA304实现精密脉冲控制方案

1. 项目背景与核心价值在嵌入式系统开发中,精确的时序控制往往是最具挑战性的环节之一。无论是工业自动化中的电机控制、医疗设备中的信号同步,还是科研实验中的精密测量,对脉冲信号的精度要求常常达到微秒甚至纳秒级。传统方案通常采用分立元…

2026/7/6 4:20:18 阅读更多 →
Python抖音机器人开发指南:从零构建智能互动系统

Python抖音机器人开发指南:从零构建智能互动系统

Python抖音机器人开发指南:从零构建智能互动系统 【免费下载链接】Douyin-Bot 😍 Python 抖音机器人,论如何在抖音上找到漂亮小姐姐? 项目地址: https://gitcode.com/gh_mirrors/do/Douyin-Bot 在当今短视频内容爆炸的时代…

2026/7/6 4:20:18 阅读更多 →

日新闻

H2 与 MySQL 单元测试兼容性:5 个关键 SQL 语句差异与规避方案

H2 与 MySQL 单元测试兼容性:5 个关键 SQL 语句差异与规避方案

H2与MySQL单元测试兼容性:5个关键SQL语句差异与规避方案1. 单元测试中的数据库兼容性挑战在Java开发领域,单元测试是保证代码质量的重要环节。当应用涉及数据库操作时,测试环境的搭建往往成为开发者的痛点。H2数据库因其轻量级、内存模式和快…

2026/7/6 0:01:17 阅读更多 →
Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘

Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘

Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘 【免费下载链接】rbtray A fork of RBTray from http://sourceforge.net/p/rbtray/code/. 项目地址: https://gitcode.com/gh_mirrors/rb/rbtray 你是否厌倦了Windows任务栏上密密麻麻的图标&…

2026/7/6 0:01:17 阅读更多 →
Visual C++ 运行时库一键安装终极指南:告别DLL缺失烦恼

Visual C++ 运行时库一键安装终极指南:告别DLL缺失烦恼

Visual C 运行时库一键安装终极指南:告别DLL缺失烦恼 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你是否曾经遇到过这样的情况:下载了…

2026/7/6 0:05:19 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/5 0:03:34 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/5 0:03:34 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/5 0:07:38 阅读更多 →

月新闻