本文聊聊 Yearnext Software Framework(以下简称 YSF),一个基于消息驱动的单片机软件框架。
https://gitee.com/accumulatedidea/Framework_Open

1. YSF 简介
YSF 全称 Yearnext Software Framework,定位是基于消息驱动的单片机软件框架,强调配置简便、跨平台、可裁剪。
如果你关心下面这几件事,值得翻一翻:
- 想把「板级驱动」和「业务逻辑」拆开,换板时知道该动哪一层
- 资源紧张的 MCU,想看协作式调度 + 消息队列,而不是一上来就上 FreeRTOS
- 想对照一套现成的
fw_conf.h 裁剪思路
它不一定适合所有人。如果你已经在成熟 RTOS / 厂商中间件上跑产品,YSF 更像架构参考,而不是替代方案。
平台也不止 README 里写的 ARM。目录和配置里能看到 8051、STM8、STM32、新唐、HC32、i.MX RT,以及 MSVC 仿真等。换板之前先确认自己的编译器和 BOARD_PALTFORM 有没有现成包。
仓库顶层大致是:compiler、hal、kernel、component、3rdparty、bsp、protocol、utility、document。

仿真工程适合先在 PC 上摸清调度与消息路径,到真板再补 MSP 与引脚配置。
2. 五层怎么读
文档写的是「五层」,但很容易和「应用层」两个字拧在一起。按职责拆开看更清楚:
硬件层 → 硬件抽象层(HAL)→ 功能模块层 → 业务逻辑层 → 应用处理层
其中后两层合起来常被称为应用层:业务逻辑负责协议、状态、具体功能;应用处理层负责把产生的消息派发到对应模块。

换板时优先动 HAL/MSP,尽量别让业务代码直接绑死寄存器级类型。
2.1 硬件层
就是板载硬件:MCU、外设、引脚。框架不会「神奇地」代替你做原理图,只要求上层通过统一接口下去。
2.2 硬件抽象层
HAL 负责把底层驱动收成统一接口,方便上层调用。它大致分三块:
- 编译器拓展包:框架专用宏、基础类型等,覆盖 Keil、IAR、SDCC、GCC、MSVC 等
- MCU 支持包(MSP):把原厂驱动接到统一的 MSP API
- 通用外设驱动包:复杂外设的工作机制
MSP 又拆成 LV0 / LV1,这是小容量平台上很实际的取舍:
- LV0:贴近芯片,可以直接操作底层,常出现原厂类型(例如
GPIO_TypeDef*)。占用小,上层可移植性弱
- LV1:标准抽象接口,把通用设备信息转成 LV0 专用信息再落硬件。可移植性更好,占用通常更大

先别急着全上 LV1。Flash/RAM 紧张、业务也不打算换平台时,LV0 往往更现实;真要跨芯片复用业务代码,再把调用面上抬到 LV1。
2.3 功能模块层
这一层是「框架能帮你省什么」的主体,分三块:
- 框架内核:小型协作式任务调度,内建定时器、事件、消息队列、状态机等;还可选 Protothread。注意有 Full 与 Nano 两套实现,设计思路接近,但 API 互不兼容,需要在
fw_conf.h 里选版本
- 功能组件(component):链表、环形缓冲区、CRC/校验和、查表、位操作等常用库
- 开源组件(3rdparty):例如 SEGGER RTT、CmBacktrace、EasyLogger,以及 FatFs、SPIFFS、SimpleGUI、LVGL 等,按需编进工程即可

消息驱动的主路径可以粗略记成:硬件或定时产生事件 → 内核排队 → 应用处理层派发 → 业务模块处理。
协作式意味着任务要主动让出 CPU。长时间死循环占着资源,别的任务就会饿着——这和抢占式 RTOS 不是一回事,写简历或做技术对标时别混为一谈。
2.4 应用层怎么串起来
业务逻辑层:协议栈、设备状态、具体功能实现。仓库里 protocol 目前能看到如 xymodem 一类协议代码,文档里该目录仍标着待补充——实际使用时以源码为准。
应用处理层:把消息派到对应处理模块。
工程上常见的落点在 bsp/<平台>/application:框架初始化、配置裁剪、应用入口都在这一带。
对照例程里的写法,主函数往往很短:
先 Fw_Core_Init(),再 Fw_Core_Startup();真正的任务用 Fw_Task_Init / Fw_Task_Start 挂上去,Protothread 打开时可用 Fw_PT_Begin / Fw_PT_Delay 这类宏把「延时让出」写清楚。例程里的 LED 翻转,就是在验证调度和板级驱动是否走通。

最小闭环可以这样走:
- 选一个接近你板子的
bsp 工程模版,例如仓库里有 STM32F1、STM32L4、simulator 等;文档里还提到过 HC32、N76E003 等模版,以你检出的目录为准
- 打开
application/fw_conf.h,选 Full/Nano、平台宏,关掉暂时用不到的组件
- 确认主流程能进内核启动;用
INIT_APP_EXPORT 一类机制注册应用初始化
- 先做一个 LED/定时任务或简单消息通路,确认调度和板级驱动通了,再叠加协议
bsp 里常见拆法:application 放应用与 fw_conf.h;paltform(仓库拼写如此)放 board、按键灯串口驱动、msp_conf.h。
3. 注意事项
- 别把协作式调度当成 RTOS:没有抢占优先级那一套预期时,任务写法要克制。中断里只做短处理,把重活投递成消息或事件,交给任务侧慢慢消化,通常更稳
- Full / Nano 不要混用 API:换版本等于换一套接口,裁剪前先定版本再写业务
- LV0 / LV1 别在业务里随意混调:抽象边界一旦糊掉,换板成本会重新回来
- 文档有空链:例如「框架内核介绍」在 README 里尚未补全,以
document/dir、kernel 源码和例程为准
- 仓库年代较老:学习分层与裁剪很合适;选型前自己评估维护状态与芯片覆盖
和「自己从零搭分层」比,YSF 的价值主要在现成的配置入口和目录约定;和「直接上 RTOS」比,它更轻,但实时性和任务隔离也弱一截。选哪条路,先看产品要不要抢占、要不要多任务硬隔离,再看 Flash 还剩多少。
4. 总结
项目不是越大越好。YSF 分层把换板成本压在 HAL/MSP;消息驱动把业务拆成可派发的处理单元;能讲清五层职责、LV0/LV1 取舍、Full/Nano 差异,这套经验就比「把整个仓抄进工程」更有用。
如果对这类轻量级消息驱动的分层架构有想法,欢迎到 云栈社区 一起聊聊。