2. 理解Marlin固件目录结构与主循环
任务说明
本案例的目标是:在Marlin固件源码中,理清顶层目录的组织方式,准确找到主循环所在文件,并理解一次主循环从准备到执行的完整调用路径。完成本案例后,你应能独立回答“Marlin启动后,CPU反复执行的循环在哪里、每轮循环做了什么”这一问题。
目录结构定位
Marlin 2.x 的源码根目录下,核心代码集中在 Marlin/ 子目录中。以下是与主循环直接相关的关键路径:
Marlin/src/— 全部固件源码Marlin/src/MarlinCore.cpp— 包含main()函数与setup()、loop()的顶层控制Marlin/src/MarlinCore.h— 相关函数声明与全局状态Marlin/src/module/— 运动控制、温度、步进电机等核心模块Marlin/src/gcode/— G代码解析与执行器Marlin/src/HAL/— 硬件抽象层,不同平台(AVR、STM32、ESP32等)的底层实现
主循环文件与运行流程
主循环并不在单独的 loop() 文件中,而是由 MarlinCore.cpp 中的 main() 函数启动后,调用 Arduino 框架的 setup() 和 loop()。其中 loop() 函数内部调用 MarlinIdle(),这是每轮主循环的核心入口。真正的“每轮循环做什么”由 MarlinIdle() 内部分发到各模块的 idle() 回调中。
一次主循环的典型执行顺序如下:
loop()被调用(由 HAL 层定时触发);- 进入
MarlinIdle(),首先调用manage_heaters()处理温度控制; - 调用
manage_inactivity()检查超时与急停状态; - 调用各模块的
idle()(如步进电机、LCD、看门狗等); - 检查是否有新的G代码命令在缓冲区中,若有则调用
GCodeParser解析并执行; - 循环结束,等待下一轮
loop()触发。
关键代码定位
在 MarlinCore.cpp 中,主循环的核心实现如下(已省略非关键代码):
// MarlinCore.cpp 中的主循环入口
void loop() {
// 每轮主循环都从这里开始
MarlinIdle();
}
void MarlinIdle() {
// 1. 温度管理
thermalManager.manage_heaters();
// 2. 空闲超时与急停检测
planner.manage_inactivity();
// 3. 各模块的周期性任务
stepper.idle();
lcd.idle();
// 4. 处理G代码命令队列
parser.parse();
}
验证方法
要验证上述理解是否正确,请按以下步骤操作:
- 在本地克隆Marlin仓库:
git clone https://github.com/MarlinFirmware/Marlin.git - 打开
Marlin/src/MarlinCore.cpp,搜索void loop()和void MarlinIdle(),确认函数存在。 - 在
MarlinIdle()函数体内,检查是否调用了thermalManager.manage_heaters()、planner.manage_inactivity()、stepper.idle()等函数。 - 在
Marlin/src/module/stepper.cpp中搜索void Stepper::idle(),确认其存在。
判定标准:若上述函数均能在对应文件中找到,且 MarlinIdle() 中的调用顺序与正文描述一致,则说明已正确定位主循环并理解其运行流程。