(学习日记)2024.03.13:UCOSIII第十五节:基于时基列表的时延操作(持续更新)

写在前面:

由于时间的不足与学习的碎片化,写博客变得有些奢侈。

但是对于记录学习(忘了以后能快速复习)的渴望一天天变得强烈。

既然如此

不如以天为单位,以时间为顺序,仅仅将博客当做一个知识学习的目录,记录笔者认为最通俗、最有帮助的资料,并尽量总结几句话指明本质,以便于日后搜索起来更加容易。

标题的结构如下:"类型":"知识点"------"简短的解释"

部分内容由于保密协议无法上传。

点击此处进入学习日记的总目录

2024.03.13

二十九、UCOSIII:基于时基列表的时延操作

1、配置时钟中断时间

c 复制代码
/* 配置SysTick 10ms 中断一次 */
	OS_CPU_SysTickInit (10);

在中断触发时运行OSTimeTick()函数

c 复制代码
/* SysTick 中断服务函数 */
void SysTick_Handler(void)
{
	OSTimeTick();
}

OSTimeTick()函数定义如下:

c 复制代码
void  OSTimeTick (void)
{
    /* 更新时基列表 */
    OS_TickListUpdate();

    /* 任务调度 */
    OSSched();
}

很明显,系统需要10ms一个时钟周期,每一个时钟周期更新一次时基列表

2、创建任务

创建任务需要使用 OSTaskCreate()函数,这部分和之前相同,不再概述。

任务指针格式如下:

c 复制代码
struct os_tcb {
    CPU_STK         *StkPtr;
    CPU_STK_SIZE    StkSize;

    /* 任务延时周期个数 */
    OS_TICK         TaskDelayTicks;

    /* 任务优先级 */
    OS_PRIO         Prio;

    /* 就绪列表双向链表的下一个指针 */
    OS_TCB          *NextPtr;
    /* 就绪列表双向链表的前一个指针 */
    OS_TCB          *PrevPtr;

    /* 时基列表相关字段 */
    OS_TCB          *TickNextPtr;
    OS_TCB          *TickPrevPtr;	
    OS_TICK_SPOKE   *TickSpokePtr;	

    OS_TICK         TickCtrMatch;	
    OS_TICK         TickRemain;		
};

3、任务放置到就绪列表中,并优先级排队

任务创建好之后,会放到就绪列表中,并在优先级列表对应值中设为1

上述在之前章节已整理,本次不再概述。

4、将任务插入时基列表

当任务需要延时时,使用OS_TickListInsert()函数将任务插入时基列表。

c 复制代码
/* 将一个任务插入时基列表,根据延时时间的大小升序排列 */
void  OS_TickListInsert (OS_TCB *p_tcb,OS_TICK time)

时基列表OSCfg_TickWheel[]OS_CFG_TICK_WHEEL_SIZE个成员。

OS_CFG_TICK_WHEEL_SIZE的推 荐值为任务数/4,不推荐使用偶数。

如果算出来是偶数,则加1变成质数,实际上质数是一个很好的选择。

时基列表OSCfg_TickWheel[]每个成员有三个值。

c 复制代码
typedefstruct  os_tick_spoke       OS_TICK_SPOKE;
//在μC/OS-III中,内核对象的数据类型都会用大写字母重新定义。

struct  os_tick_spoke {
    OS_TCB              *FirstPtr;
    //每个成员都包含一条单向链表, 被插入该条链表的TCB会按照延时时间做升序排列。
    //FirstPtr用于指向这条单向链表的第一个节点。
    
    OS_OBJ_QTY           NbrEntries;
    //NbrEntries表示该条单向链表当前有多少个节点。
    
    OS_OBJ_QTY           NbrEntriesMax;
    //NbrEntriesMax记录该条单向链表最多的时候有多少个节点, 在增加节点的时候会刷新,在删除节点的时候不刷新。
};

1. 确认时延

当任务需要插入到时基列表中时,首先需要确认需要时延几个周期,即TickRemain的值。

然后确认OSTickCtr的值,将TickRemainOSTickCtr相加得到TickCtrMatch

OSTickCtr是一个全局变量, 记录的是系统自启动以来或者自上次复位以来经过了多少个SysTick周期。
OSTickCtr的值每经过一个SysTick周期其值就加一

2.对任务进行排序

众所周知,任务随时都有可能加入到时基列表中,那么怎么能高效的将各个任务按时延长短进行排序,并快速取用呢?

答案就在TickCtrMatch这个变量上,TickCtrMatch变量是系统设计时的一个巧思妙想。

当一个任务需要插入时基列表中时,我们先获得TickCtrMatch值。

因为TickCtrMatch值是TickRemainOSTickCtr的和,即当前时间+时延时间,得到的值就是时延结束的绝对时间

这样就能将所有任务按照 实验结束的绝对时间 进行排序。

3. 确认插入时基列表哪个成员

TickCtrMatchOS_CFG_TICK_WHEEL_SIZE进行求余,即对成员总数进行求余,得到的数就是存放任务的下标。

这样做是为了对任务进行分类。

假如成员总数为10(但实际上应该是个质数),当前系统时间为502
50210求余得2,那么在任务时延结束绝对时间TickCtrMatch502,513,515,522的几个任务里只有502,522余数为2。我们不需要跟其他数比,只需要在余数为2的任务里找就行,这样就可以极大的减少寻找时间

同时将余数相同的任务按顺序排列,那么当系统时间为502,任务时延结束的绝对时间为522,那么之后的任务就不需要再找了,因为一定会比522大。

4. 对就绪列表的操作

当任务加入到时基列表中后,就需要从就绪列表中删除。

时基列表OSCfg_TickWheel[]该成员的NbrEntries加1。

当任务任务时延结束绝对时间TickCtrMatch等于系统时间OSTickCtr时就把任务加入到就绪列表,并从时基列表中删除。

时基列表OSCfg_TickWheel[]该成员的NbrEntries减1。

每个时间循环都要确定NbrEntriesMax大于等于NbrEntries

相关推荐
声网2 小时前
OpenAI Realtime API 重磅更新:锚定语音模型「深度推理+自主执行」演进路径|Voice Agent 学习笔记
笔记·学习
前端摸鱼匠3 小时前
【AI大模型春招面试题31】什么是“零样本学习(Zero-Shot)”“少样本学习(Few-Shot)”?大模型实现这类能力的核心原因?
人工智能·学习·面试·大模型·求职招聘
薛定猫AI4 小时前
【深度解析】Hermes Agent:持久记忆、自学习闭环与桌面化 Autonomous AI 工作流实践
人工智能·学习
iCxhust4 小时前
8086/8088单板机VSCode集成自动下载功能(完善串口接收显示版)
ide·vscode·单片机·编辑器·微机原理·8088单板机·8086单板机
老虎06274 小时前
黑马程序员苍穹外卖--学习笔记(苍穹外卖万字总结—重点知识,面试常见问题)超全
笔记·学习·面试
sealaugh324 小时前
react native(学习笔记第四课) 英语打卡微应用(3)-ocr的文字转化成语音文件(tts)
笔记·学习·react native
小新同学^O^4 小时前
简单学习 --> SpringAOP
java·学习·spring·aop
炽烈小老头4 小时前
【每天学习一点算法 2026/05/10】合并K个排序链表
学习·算法·链表
wuxinyan1234 小时前
大模型学习之路010:RAG 零基础入门教程(第六篇):重排序技术
人工智能·学习·rag
Bruce_kaizy4 小时前
c++ linux环境编程——从应用层到linux内核深入了解文件io的调用机制(爆肝)
linux·c++·c·嵌入式linux·文件io