第二章:需求分析与系统架构设计——如何将模糊的“想法”转化为明确的技术需求

大家好,我是你们的老朋友。上一章我们聊了怎么从零开始搭一个Demo,很多同学反馈说「想法有了,但一到写需求就懵」。嗯,这其实是个普遍问题。我见过太多项目,前期需求没理清,后期改得想哭。今天我们就来聊聊,怎么把老板嘴里那句「做个智能控制器」变成能落地的技术文档。

一、从「一句话需求」到「功能列表」

先讲个我自己的经历。几年前接了个项目,客户说「我要一个能远程控制的温控器」。听起来简单吧?结果一细问,远程控制是走WiFi还是蓝牙?要不要本地脱机运行?温度精度要求多少?客户全懵了。

所以第一步,我习惯用「5W1H」法把模糊想法拆开:

  • Who:谁用这个设备?操作员?维护人员?最终用户?
  • What:核心功能是什么?控制、监测、报警、记录?
  • Where:用在什么环境?室内、户外、高温、潮湿?
  • When:是持续运行还是间歇工作?响应时间要求?
  • Why:为什么要做这个功能?有没有替代方案?
  • How:怎么实现?硬件选型、通信方式、成本约束。

举个例子,把「智能控制器」拆开,你会得到类似这样的表格:

模糊描述 明确需求
远程控制 支持WiFi连接,手机APP可开关设备,延迟≤2秒
温度监测 精度±0.5℃,采样周期1秒,超限报警
本地操作 实体按键+OLED显示,无网络时仍可手动控制
数据记录 本地存储最近7天数据,支持USB导出
我的小技巧: 每次拿到需求,先写一个「功能清单」,然后挨个问「如果这个功能不做,会怎样?」。能砍掉的,说明不是核心需求。

二、系统架构图——用SVG画出你的「骨架」

需求理清了,下一步就是画架构图。我个人习惯先画一个「黑盒图」,只标输入输出,不关心内部怎么实现。然后再一层层拆开。

下面是我用SVG画的一个典型嵌入式控制系统架构图。你看,它分了三层:感知层、控制层、交互层。每一层只管自己的事,互不干扰。

嵌入式控制系统架构图 感知层(输入) 温度传感器 | 湿度传感器 | 按键输入 | 通信接口(WiFi/蓝牙) 控制层(核心处理) MCU主控 | 控制算法(PID/阈值) | 数据存储 | 逻辑判断 交互层(输出) OLED显示 | 继电器/电机驱动 | 蜂鸣器报警 | 云端数据上报 传感器数据流 控制指令流

你看,这张图一画出来,整个系统的边界就清楚了。硬件工程师知道要选什么传感器,软件工程师知道要写哪些驱动,测试人员也知道测什么。

核心原则: 架构图不是画得越细越好。我建议控制在3-5层,每层只标关键模块。太细了反而让人看不清重点。

三、模块划分原则——别让代码变成「一锅粥」

架构图有了,接下来就是切模块。说实话,模块划分是门手艺活。我见过最惨的项目,一个.c文件写了8000行,改一个bug要翻半天。为什么会这样?因为一开始就没想好怎么切。

我总结了三个原则,你写代码前可以对照着看看:

  1. 高内聚、低耦合:每个模块只做一件事,模块之间通过接口通信,别互相调内部变量。比如温度采集模块,只管读传感器数据,别管数据怎么显示。
  2. 接口稳定、实现可变:模块的.h文件定义好接口后,尽量别改。内部实现随便换,今天用DS18B20,明天换NTC,只要接口不变,其他模块不用动。
  3. 可测试性优先:每个模块最好能独立测试。我习惯给每个模块写一个test_main.c,单独编译运行。这样调试时不用烧录整个固件,省时间。
避坑指南: 我曾经在一个项目里,把WiFi驱动和业务逻辑写在同一个文件里。结果WiFi模块换型号时,业务逻辑全得重写。后来我学乖了,驱动层和业务层必须分开,中间加一个抽象层。

四、从需求到模块的映射——一个实战例子

光说理论太干,我们拿一个「智能灌溉控制器」来走一遍流程。

原始需求:「做个自动浇花的设备,能根据土壤湿度自动浇水,也能手机控制。」

第一步:拆需求

  • 土壤湿度检测:精度±3%,每10秒采样一次
  • 自动控制:湿度低于阈值时开启电磁阀,高于阈值关闭
  • 手机控制:通过WiFi连接,可手动开关、查看状态
  • 本地操作:实体按键+LED指示
  • 安全保护:电磁阀连续开启不超过30分钟

第二步:画模块图

我习惯用表格来映射模块和需求:

模块名称 对应需求 输入接口 输出接口
soil_sensor.c 土壤湿度检测 ADC通道号 湿度值(0-100%)
valve_ctrl.c 电磁阀控制 开关指令 GPIO电平
auto_ctrl.c 自动控制逻辑 湿度值、阈值 开关指令
wifi_mgr.c WiFi通信 APP指令 状态数据
ui_local.c 本地按键+LED 按键事件 LED状态
safety.c 安全保护 电磁阀开启时间 强制关闭指令

你看,每个模块的职责清清楚楚。写代码时,你只需要关注当前模块,不用管别的。这就是模块化的好处。

我的习惯: 每个模块的.c文件开头,我都会写一段注释,说明这个模块「负责什么」「依赖哪些模块」「输出什么」。这样半年后回来看代码,自己也能快速想起来。

五、需求变更怎么办?——留好「扩展点」

做嵌入式开发,需求变更是常态。我遇到过最夸张的,产品都试产了,客户说要加一个OTA升级功能。怎么办?

我的做法是:在架构设计时,就预留一些「扩展点」。比如:

  • 通信模块:不要写死成WiFi,用抽象接口,以后换4G、LoRa都行
  • 传感器模块:用统一的read()接口,换传感器只需改底层驱动
  • 控制逻辑:把阈值、参数做成可配置的,存在EEPROM里,不用改代码

说白了,就是「面向接口编程,不要面向实现编程」。这个道理很多书上都讲过,但真正能做到的,都是在项目里吃过亏的。

好了,这一章的内容就到这里。需求分析和架构设计,说白了就是「想清楚再动手」。你花在前期的时间,会在后期十倍百倍地省回来。下一章我们聊具体怎么把架构图变成代码,到时候见。


公众号:蓝海资料掘金营,微信deep3321