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

相关推荐
大丈夫立于天地间19 分钟前
ISIS基础知识
网络·网络协议·学习·智能路由器·信息与通信
山羊硬件Time33 分钟前
详解单片机学的是什么?(电子硬件)
单片机·硬件工程师·硬件开发·电子工程师·电子硬件
Chambor_mak1 小时前
stm32单片机个人学习笔记14(USART串口数据包)
stm32·单片机·学习
tadus_zeng1 小时前
51单片机(三) UART协议与串口通信实验
单片机·嵌入式硬件·51单片机
ZLG_zhiyuan2 小时前
ZLG嵌入式笔记 | 电源设计避坑(下)
单片机·嵌入式硬件
PaLu-LI2 小时前
ORB-SLAM2源码学习:Initializer.cc⑧: Initializer::CheckRT检验三角化结果
c++·人工智能·opencv·学习·ubuntu·计算机视觉
yuanbenshidiaos2 小时前
【大数据】机器学习----------计算机学习理论
大数据·学习·机器学习
汤姆和佩琦2 小时前
2025-1-20-sklearn学习(42) 使用scikit-learn计算 钿车罗帕,相逢处,自有暗尘随马。
人工智能·python·学习·机器学习·scikit-learn·sklearn
Tech智汇站3 小时前
Quick Startup,快捷处理自启程序的工具,加快电脑开机速度!
经验分享·科技·学习·学习方法·改行学it
qq_312738453 小时前
jvm学习总结
jvm·学习