tzz1983 发表于 2025-4-12 10:59:26

协程OSFrame@AI8H,最简代码实现多任务阻塞,替代 switch 状态机

前言:
本帖的前身是 “裸机编程框架, 可以显示CPU使用率”.
近日在看到 王同学的 【协程方式】实现【多任务调度 / 多线程】 帖时.
突然想到裸机编程也可以利用OS的阻塞原理并用简单代码实现.
于是就出现了这个 协程OSFrame@AI8H

特点:
*    这是一个协程OS,但完全继承了祼机的简洁,每个任务仅占用 4ByteRAM,code 仅占用 478byte
*    符合OS的编程习惯,每个任务中一个while(1)循环。
*    因为是协程,没有RTOS中的重入问题,当然也没有信号量这一块。这也是代码为何这么简单的原因
*    用 TaskTickDly() 替代 switch 状态机,使代码看起来就像是顺序执行,编程逻辑变简单了。
*    已实现了CPU使用率统计功能。利于开发阶段调试。
*    效率极高,任务切换就像发生了一次return,几乎没有额外的CPU损耗。

用法详细介绍:先看看任务函数 TaskA:
代码中用两个 TaskTickDly() 函数来点亮LED闪烁,
演示了下次运行时,是从TaskTickDly() 函数的下一句开始执行的。即断点续继执行
每个任务都是一个while(1) 死循环,看起来并不需要返回,是不是有OS的感觉了.
实际是上 TaskTickDly()会跳出任务。

void TaskA(void)
{
    TaskStart();    //任务开始, 此句不能省略   
    while(1)
    {
      LED = 1;
      TaskTickDly(500);   //阻塞延时500个时钟滴答,演示断点继续功能
      LED = 0;
      TaskTickDly(500);   //阻塞延时500个时钟滴答,演示断点继续功能
    }
}


OSFrame系统服务仅两个 ,分别为:
TaskStart()    //这是一个宏,此宏定义了任务所需的静态变量并初始化。
TaskTickDly()//也是一个宏,实现阻塞功能。


范例中的另外两个任务:
/*---------------------------------------------------------
TaskB 扫描串口,接收数据
----------------------------------------------------------*/

void TaskB(void)
{
    TaskStart();    //任务开始, 此句不能省略   
    while(1)
    {
      Uart_Polling();   //扫描串口,接收数据
      TaskTickDly(20);    //阻塞延时20个时钟滴答
    }
}

/*---------------------------------------------------------
TaskC打印CPU使用率
----------------------------------------------------------*/
void TaskC(void)
{
    TaskStart();    //任务开始, 此句不能省略
    while(1)
    {
      #if USE_STATISTICAL
            printf("CPU使用率为: %u.",CPUUsage/10U); printf("%u%%\r\n",CPUUsage%10U);
      #endif
      TaskTickDly(1000);      //阻塞延时1000个时钟滴答
    }
}




调度器:即创建任务
/*---------------------------------------------------------
调度器顶端, TICK_hook() 每滴答被调用一次
---------------------------------------------------------*/
void TICK_hook(void)
{
    TaskA();    //每个任务函数都在此调用
    TaskB();
    TaskC();
    WDT_CONTR = 0X37;   //启用看门狗
}


另外,代码中还包含了两个可选项。适应多种场景,
    Main_Polling(),启用后,只要CPU有空闲时间,就不断的重复调用 Main_Polling()
    Timer0_Ihook() ,启用后,每滴答调用一次 Timer0_Ihook()这个是中断调用
我认为这个框架可以替代大部分祼机编程,作为项目编程的一个起点


协程OSFrame@AI8H




补充说明:
*    TaskStart()   TaskTickDly()目前只支持在任务函数中调用
*    任务函数中如果有局部变量,要加static, 这是因为 KEIL C51存在变量分析覆盖,
出就是说任务函数中只能定义静态局部变量。以避免 TaskTickDly() 阻塞 任务时,其它任务改变了函数体中的局部变量值。
TaskTickDly() 阻塞 任务时,编译器并不知道你已经退出了函数。


要改进这两个限制也不难,不过先就这样吧,这东西也是随兴而起,哪天自己用到了,再折腾也不迟









国芯人工智能 发表于 2025-4-12 11:03:00

协程OSFrame@AI8H的设计理念确实为裸机编程提供了一种简洁且高效的多任务处理方案。以下是对该框架的进一步分析和优化建议:

1. 协程与裸机编程的结合
协程(Coroutine)是一种轻量级的线程,能够在执行过程中暂停和恢复。与传统的RTOS相比,协程不需要复杂的上下文切换和资源管理,因此在资源受限的嵌入式系统中具有显著优势。协程OSFrame@AI8H通过协程机制实现了多任务调度,同时保持了裸机编程的简洁性。

2. 任务管理与阻塞机制
在协程OSFrame@AI8H中,每个任务通过TaskTickDly()函数实现阻塞延时。该函数不仅实现了任务的暂停,还确保了任务在恢复时从上次暂停的位置继续执行。这种机制替代了传统的switch状态机,使得代码逻辑更加清晰,易于维护。

3. 资源占用与性能优化
每个任务仅占用4字节的RAM,代码占用478字节,这在资源受限的嵌入式系统中是非常高效的。然而,为了进一步提升性能,可以考虑以下优化措施:
任务优先级:引入简单的任务优先级机制,确保高优先级任务能够及时响应。
事件驱动:结合事件驱动机制,减少不必要的任务轮询,降低CPU使用率。
内存管理:优化内存分配策略,减少内存碎片,提高系统稳定性。

4. CPU使用率统计
CPU使用率统计功能对于系统调试和性能优化至关重要。协程OSFrame@AI8H已经实现了该功能,但可以进一步扩展:
任务级统计:统计每个任务的CPU使用率,帮助开发者识别性能瓶颈。
历史数据:记录历史CPU使用率数据,便于分析系统负载变化。

5. 代码示例与优化
以下是一个优化后的任务函数示例,展示了如何利用协程OSFrame@AI8H实现多任务处理:

c
void TaskA(void)
{
    TaskStart();    // 任务开始, 此句不能省略   
    while(1)
    {
      LED = 1;
      TaskTickDly(500);   // 阻塞延时500个时钟滴答,演示断点继续功能
      LED = 0;
      TaskTickDly(500);   // 阻塞延时500个时钟滴答
    }
}

void TaskB(void)
{
    TaskStart();    // 任务开始, 此句不能省略   
    while(1)
    {
      // 执行其他任务逻辑
      TaskTickDly(100);   // 阻塞延时100个时钟滴答
    }
}

6. 总结
协程OSFrame@AI8H通过协程机制实现了高效的多任务处理,同时保持了裸机编程的简洁性。通过进一步优化任务管理、资源占用和CPU使用率统计功能,可以进一步提升系统的性能和稳定性。该框架为嵌入式系统开发者提供了一种新的思路,值得在实际项目中推广应用。

希望以上分析和建议能够对协程OSFrame@AI8H的进一步发展和优化提供参考。

[本文内容由国芯人工智能辅助生成,仅供参考]

xhbwork 发表于 2025-4-22 09:05:29

不错,很简洁,有个详细文档也许更容易理解
页: [1]
查看完整版本: 协程OSFrame@AI8H,最简代码实现多任务阻塞,替代 switch 状态机