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 底下什么也没有 我代码呢 我内核呢作者有一个小巧思 他分离了主仓库和子仓库 纯净内核仓库只给单片机用仓库地址其实是github.com/TECREA/QuarkTS这个仓库里极其干净只有 16 个.c和 20 个.h没有任何杂质专供我们这种嵌入式工程师引用。综合开发大仓库刚才 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) { ; } }