基于链表管理的单片机轮询程序框架
内容提要
本文介绍了单片机裸机程序框架的重要性,以及如何使用时间片轮询框架来实现该框架的完全解耦。通过示例代码展示了如何创建任务并加入到时间片轮询的框架中。文章还介绍了底层侵入式双向链表的使用。该框架使用方便,可以快速创建任务并加入到时间片轮询中。
延伸解读
解耦设计:业务代码与框架分离
文章强调时间片轮询框架通过接口函数注册任务,用户只需包含头文件,无需修改库文件。这种设计借鉴了实时操作系统的低耦合思路,将任务对象与调度逻辑分离。实际开发中,这意味着新增或删除任务只需调用timeslice_task_add/del,不必改动框架源码,降低了维护成本,也便于团队协作。
侵入式链表的效率与代价
框架底层采用侵入式双向链表管理任务,参考RT-Thread实现。链表节点内嵌在任务结构体中,避免了额外内存分配,遍历和增删操作效率高。但这也要求任务对象必须包含ListObj成员,且链表操作需谨慎处理指针,否则易引发内存错误。适合资源受限的单片机环境,但需开发者对链表原理有基本理解。
时间片调度的运行机制
timeslice_tick递减每个任务的timer,归零时置is_run为TASK_RUN并重置timer;timeslice_exec遍历链表,执行is_run为TASK_RUN的任务后将其置为TASK_STOP。这种设计确保任务按设定周期运行,且每次tick只触发一次。示例中通过两个线程模拟定时器中断和主循环调度,展示了裸机环境下时间片轮询的基本工作流程。
适用场景与注意事项
该框架适合裸机单片机中需要多任务周期调度的场景,接口简单,可快速创建任务。但文章未涉及任务优先级、阻塞或抢占,所有任务按链表顺序轮询执行,长任务可能影响其他任务实时性。此外,示例代码在PC上模拟,移植到单片机需适配定时器和主循环。开发者应评估任务执行时间,避免因单任务过长导致调度延迟。
Q&A
单片机裸机程序为什么需要重视程序框架设计?
良好的代码架构设计可以提高编写效率和调试效果。初学者常一点一点写代码,缺乏整体规划,导致后期代码混乱、bug增多,增加新功能时浪费大量时间甚至崩溃。项目开始时花时间设计架构非常必要。
时间片轮询框架如何实现与业务代码的完全解耦?
借鉴实时操作系统的思维方式,用户只需包含头文件,通过接口函数注册业务代码,无需修改库文件。框架使用结构体作为对象,通过侵入式双向链表管理任务,实现完全解耦。
如何使用时间片轮询框架创建并添加任务?
首先定义TimesilceTaskObj类型的任务对象,然后调用timeslice_task_init初始化任务(指定任务函数、ID和时间片长度),再调用timeslice_task_add将任务加入调度链表。示例中创建了5个任务并依次添加。
时间片轮询框架中的任务调度是如何工作的?
框架通过timeslice_tick在定时器中断中递减每个任务的timer,当timer减到0时设置任务为运行状态并重置timer;timeslice_exec在主循环中遍历任务链表,执行处于运行状态的任务,执行后将其状态置为停止。
框架底层使用的侵入式双向链表有什么特点?
该链表参考RT-Thread实时操作系统的实现,在Linux内核中广泛使用。它通过ListObj结构体嵌入到任务对象中,提供初始化、插入、删除、判空、长度计算等操作,使用container_of宏从链表节点获取宿主结构体,高效且节省资源。
时间片轮询框架提供了哪些接口函数来管理任务?
主要接口包括:timeslice_task_init(初始化任务)、timeslice_task_add(添加任务)、timeslice_task_del(删除任务)、timeslice_get_task_num(获取任务数量)、timeslice_get_task_timeslice_len(获取任务时间片长度)、timeslice_task_isexist(判断任务是否存在),以及timeslice_exec和timeslice_tick用于调度。