(学习日记)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

相关推荐
yunhuibin23 分钟前
ffmpeg面向对象——参数配置秘密探索及其设计模式
学习·设计模式·ffmpeg
玄客)1 小时前
MACCMS 远程命令执行漏洞复现(CVE-2017-17733)
学习·安全
天蓝蓝235281 小时前
嵌入式硬件基础知识
嵌入式硬件
代码总长两年半1 小时前
STM32+FATFS+SD卡+RTC(生成.CSV格式文件)
stm32·嵌入式硬件·实时音视频
HinsCoder2 小时前
【渗透测试】——Upload靶场实战(1-5关)
笔记·学习·安全·web安全·渗透测试·测试·upload靶场
听风若依2 小时前
排序学习笔记
笔记·学习
Filotimo_2 小时前
【自然语言处理】实验三:新冠病毒的FAQ问答系统
人工智能·经验分享·笔记·python·学习·自然语言处理·pycharm
IM_DALLA2 小时前
【Verilog学习日常】—牛客网刷题—Verilog快速入门—VL21
学习·fpga开发
狐心kitsune2 小时前
erlang学习:Linux常用命令1
linux·学习·erlang
小游鱼KF2 小时前
Spring学习前置知识
java·学习·spring