☰
从零开始给自己的单片机移植 QuarkTS 操作系统
2026/10/11 22:44:24 网站建设 项目流程

0. QuarKTS介绍

QuarkTS是一个专为资源高度受限的微控制器(8 位、16 位和 32 位 MCU)设计的开源、轻量级协作式多任务嵌入式操作系统(OS / 任务调度内核)。

与 FreeRTOS、RT-Thread 等重量级抢占式 RTOS 相比,QuarkTS 的定位更偏向于事件驱动型的超轻量级运行环境,其核心架构与特性如下:

一、 核心架构与特点

1. 共享栈设计与极低 RAM 占用
  • 传统 RTOS(如 FreeRTOS):每个任务(Task)必须分配一块独立的任务堆栈(Stack,通常几百字节到几 KB),多开几个任务对小容量 RAM 的 MCU(如 2KB~8KB RAM)负担极大。

  • QuarkTS:采用运行至完成(Run-to-Completion)机制,所有任务共享同一个系统调用栈。系统启动一个任务仅消耗几十字节的任务控制块(TCB)内存,在极小 RAM 甚至 8 位单片机(PIC、AVR、STM8、8051)上也能轻松运行。

2. 调度机制:协作式 + 事件驱动
  • 非抢占协作式:任务默认由事件触发或周期调度,任务执行完毕后主动退出交出 CPU 控制权。虽然避免了复杂的汇编级上下文切换(Context Switch),但要求每个任务不能有长延时死等(如禁止直接调用delay_ms())。

  • 优先级与队列支持:支持任务优先级,当多个事件同时发生时,高优先级任务优先排队执行。

3. 开箱即用的丰富外围组件

QuarkTS 虽小,但内部封装了一套完整的嵌入式工程工具链,无需外挂第三方库:

  • 分层状态机(HSM - Hierarchical State Machine):原生支持状态嵌套、进出动作,非常适合处理复杂的业务逻辑(如汽车灯光模式切换、按键状态机)。

  • 软件定时器(Software Timers):只需提供一个物理 Tick(如 SysTick),即可派生无限数量的低开销软定时器。

  • 任务间通信(IPC):内建消息队列(Queues)、通知(Notifications)和事件标志(Event Flags)。

  • 内存池管理(Memory Pools):提供固定尺寸的安全内存池,杜绝堆碎片化。

  • 简易 CLI 命令行接口:自带命令行解析器,方便串口调试。

4. 纯 ANSI-C 编写,极高移植性
  • 核心代码不依赖特定芯片架构的汇编指令(如中断压栈切换),只要支持标准 C 语言编译器,基本只需对接一个系统硬件时钟节拍(Tick 函数),即可在任意 MCU 上跑起来。

1. 先需要搞到QuarkTS的源码

github仓库链接如下

kmilo17pet/QuarkTS: 一个支持优先级协作调度、时间控制、任务间通信原语、分层状态机和 CoRoutines 的开源嵌入式应用操作系统。 --- kmilo17pet/QuarkTS: An open-source OS for embedded applications that supports prioritized cooperative scheduling, time control, inter-task communications primitives, hierarchical state machines and CoRoutines.https://github.com/kmilo17pet/QuarkTS

你Clone完会发现 QuarkTS\src\os 底下什么也没有 我代码呢? 我内核呢??

作者有一个小巧思 他分离了主仓库和子仓库 :

  1. 纯净内核仓库(只给单片机用):
    • 仓库地址其实是:github.com/TECREA/QuarkTS
    • 这个仓库里极其干净,只有 16 个.c和 20 个.h,没有任何杂质,专供我们这种嵌入式工程师引用。
  2. 综合开发大仓库(刚才 Clone 的这个):
    • 仓库地址是:github.com/kmilo17pet/QuarkTS
    • 这是作者自己的完整工作台。它里面包含了:
      • 内核代码(通过子模块链接到仓库 1);
      • 官方用户手册(通过子模块链接到说明书仓库);
      • 电脑仿真测试工具(x86 单元测试、代码质量检查等)。

破解方法如下:

招式 1:克隆时直接带递归参数(最省事,一步到位)

git clone --recursive https://github.com/kmilo17pet/QuarkTS.git

加了--recursive(递归)参数,Git 就会自动把仓库里嵌套的所有子模块仓库全部一口气下载齐全!

招式 2:如果已经 clone 完了,在文件夹里补一条命令

git submodule update --init --recursive

此时就可以发现我们的关键文件就有了

2. 复制源码中的内核文件到我们的工程文件夹中

首先需要复制的文件如下

└── QuarkTS/ ├── include/ <-- 整个 include 文件夹(里面是 QuarkTS.h, qconfig.h 等) ├── qkernel.c <-- 调度器核心 ├── qtasks.c <-- 任务管理 ├── qclock.c <-- 时间基准 ├── qfsm.c <-- 状态机 ├── qqueues.c <-- 队列 ├── qstimers.c <-- 软件定时器 ├── qresponse.c ├── qmemmang.c ├── qlists.c ├── qioutils.c ├── qedgecheck.c ├── qcritical.c ├── qcoroutine.c ├── qbsbuffers.c └── qatcli.c

也就是说把你Clone的QuarkTS-7.3.3下的include文件夹和所有.c文件拷到你自己的工程文件夹下 你可以自己建自己的文件夹方便管理 我这里使用的是 RTOS/QuarkTS

然后还要把你Clone的QuarkTS-7.3.3下的这个路径里面的 qconfig.h 这个文件放在**include文件夹内 补好最后一张拼图

可以参考一下我的工程目录 include文件夹内 还多一个qconfig.h 哦!

我的工程目录参考如下

3. 打通构建系统(CMakeLists.txt)

在CMakeLists.txt中加入
加上 RTOS/ QuarkTS / include
加上 RTOS/ QuarkTS / * .c (每个人的放的路径和名字不一样,我放我的作为参考)

加完之后保存 然后用cmake构建一下 发现文件已经被加入进去了

而且发现整个 QuarkTS 内核编进来,居然只占用了56 个字节的 RAM!这就是在 6KB 小芯片上选协作式单堆栈操作系统的意义所在!

4. 由你手写板级胶水层(xxx.c 和 xxx.h)

那么如何把刚刚加进去的操作系统和我们的单片机代码耦合起来,让他们正常工作呢,这时候就需要自己写一个驱动,把他们两“粘起来” 。

我这里的驱动文件名称就命名为app_os.c和.h了,自己看懂自己新建的文件即可。

主要任务如下(5ms任务是我自己加的 每个

人任务不同):
├── 配置硬件 1ms SysTick 心跳
├── 创建 5ms 车灯任务句柄(qTask_t)与回调函数(把 ADC_5ms_Task 和 Output_5ms_Task 放进去)
└── 编写 Init_OS( ):设置 1ms 时基 -> 注册任务 -> qOS_Run() 启动调度

我以我的简单嵌入式车灯代码为例:

第一步:新建App/app_os.h

#ifndef _APP_OS_H_ #define _APP_OS_H_ /* 启动车灯操作系统调度 */ void Init_App_OS(void); #endif /* _APP_OS_H_ */

第二步:新建App/app_os.c

#include "app_os.h" #include "QuarkTS.h" #include "cps32k21x.h" #include "adc_drv.h" #include "output.h" #define SYSTEM_CLOCK_HZ (48000000UL) // 芯片主频 48MHz #define OS_TICK_HZ (1000UL) // OS 滴答频率 1000Hz (1ms 节拍) /* 1. 定义 5ms 车灯任务控制块(句柄) */ static qTask_t m5ms_task; /* 2. 编写 5ms 任务回调函数(把之前裸机 while(1) 里的业务搬进来) */ static void M5ms_Task_Callback(qEvent_t e) { (void)e; ADC_5ms_Task(); // 5ms 采样滤波 Output_5ms_Task(); // 5ms 状态机决策 } /* 3. 空闲任务回调(没有任务就绪时执行,留空即可) */ static void Idle_Callback(qEvent_t e) { (void)e; } /* 4. 配置单片机硬件 SysTick(每 1ms 触发一次 SysTick_Handler 中断) */ static void Hardware_SysTick_Init(void) { SysTick_Config(SYSTEM_CLOCK_HZ / OS_TICK_HZ); // 48000 个周期 = 1ms } /* 5. 胶水层主入口函数 */ void Init_App_OS(void) { /* 5.1 初始化 QuarkTS 内核时基 (0.001f 表示以 1ms 为基准) */ qOS_Setup( NULL , 0.001f, Idle_Callback NULL ); /* 5.2 添加 5ms 周期任务 (间隔 0.005 秒,周期运行,默认使能) */ qOS_Add_Task(&m5ms_task, M5ms_Task_Callback, qMedium_Priority, 0.005f, qPeriodic, qEnabled, NULL); /* 5.3 启动硬件 1ms 滴答定时器 */ Hardware_SysTick_Init(); /* 5.4 正式移交权力,启动操作系统调度循环(永不返回!) */ qOS_Run(); }

第三步:在 App/interrupt.c 注入心跳

找到第 26 行原本空着的SysTick_Handler函数,把 QuarkTS 的心跳推动函数注入进去:

#include "QuarkTS.h" // 记得顶部引用一下头文件 extern void qClock_SysTick(void); void SysTick_Handler(void) { qClock_SysTick(); /* 每 1ms 中断触发一次,推动 QuarkTS 内核时间指针前进 1ms */ }

5. 在 main.c 中交接指挥权 !

└── 初始化完硬件后,调用 Init_OS( ),进入操作系统调度循环!
直接上代码

#include "main.h" #include "adc_drv.h" #include "gpio_drv.h" #include "output.h" #include "app_os.h" // 包含我们的胶水层头文件 int main(void) { ErrorStatus status = ERROR; status = RCC_SysClk_SwitchTo_PLL(RCC, PLL_INPUT_SOURCE_HIRC, SET_PLL_FREQ_48MHz); while (status != SUCCESS) { status = RCC_SysClk_SwitchTo_PLL(RCC, PLL_INPUT_SOURCE_HIRC, SET_PLL_FREQ_48MHz); } /* 1. 单片机外设硬件初始化 */ Init_GPIO(); Init_ADC(); Init_Output(); /* 2. 移交控制权给操作系统(进入 qOS_Run 循环,不再返回) */ Init_App_OS(); /* 3. 保底死循环 */ while (1) { ; } }

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询