(学习日记)2024.03.06:UCOSIII第八节:空闲任务+阻塞延时+main函数修改

写在前面:
由于时间的不足与学习的碎片化,写博客变得有些奢侈。
但是对于记录学习(忘了以后能快速复习)的渴望一天天变得强烈。
既然如此
不如以天为单位,以时间为顺序,仅仅将博客当做一个知识学习的目录,记录笔者认为最通俗、最有帮助的资料,并尽量总结几句话指明本质,以便于日后搜索起来更加容易。


标题的结构如下:“类型”:“知识点”——“简短的解释”
部分内容由于保密协议无法上传。


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

2024.03.05

  • 十八、UCOSIII:空闲任务
    • 1、阻塞延时与空闲任务介绍
    • 2、定义空闲任务栈
    • 3、定义空闲任务TCB
    • 4、定义空闲任务函数
    • 5、空闲任务初始化
  • 十九、UCOSIII:实现阻塞延时
    • 1、阻塞延时函数
    • 2、记录任务需要延时的时间
    • 3、任务切换的部分修改
  • 二十、UCOSIII:修改main()函数
    • 1、程序代码
    • 2、编译调试

十八、UCOSIII:空闲任务

1、阻塞延时与空闲任务介绍

在之前的十七章中,任务体内的延时使用的是软件延时,即让CPU空等来达到延时的效果。
使用RTOS的很大优势就是榨干CPU的性能, 永远不能让它闲着,任务如果需要延时也就不能再让CPU空等来实现延时的效果。

RTOS中的延时叫阻塞延时,即任务需要延时的时候, 任务会放弃CPU的使用权,CPU可以去干其他的事情,当任务延时时间到,重新获取CPU使用权,任务继续运行, 这样就充分地利用了CPU的资源,而不是干等着。

当任务需要延时,进入阻塞状态,那CPU又去干什么事情了?
如果没有其他任务可以运行,RTOS都会为CPU创建一个空闲任务, 这个时候CPU就运行空闲任务。

在μC/OS-III中,空闲任务是系统在初始化的时候创建的优先级最低的任务,空闲任务主体很简单, 只是对一个全局变量进行计数。
鉴于空闲任务的这种特性,在实际应用中,当系统进入空闲任务的时候, 可在空闲任务中让单片机进入休眠或者低功耗等操作。

2、定义空闲任务栈

空闲任务栈在os_cfg_app.c文件中定义
在这里插入图片描述

#include <os_cfg_app.h>
#include <os.h>/*
************************************************************************************************************************
*                                                    DATA STORAGE
************************************************************************************************************************
*/CPU_STK        OSCfg_IdleTaskStk   [OS_CFG_IDLE_TASK_STK_SIZE];/*
************************************************************************************************************************
*                                                      CONSTANTS
************************************************************************************************************************
*//* 空闲任务堆栈起始地址 */
CPU_STK      * const  OSCfg_IdleTaskStkBasePtr   = (CPU_STK    *)&OSCfg_IdleTaskStk[0];
/* 空闲任务堆栈大小 */
CPU_STK_SIZE   const  OSCfg_IdleTaskStkSize      = (CPU_STK_SIZE)OS_CFG_IDLE_TASK_STK_SIZE;
  • CPU_STK OSCfg_IdleTaskStk [OS_CFG_IDLE_TASK_STK_SIZE];
    空闲任务的栈是一个定义好的数组,大小由OS_CFG_IDLE_TASK_STK_SIZE这个宏控制。 OS_CFG_IDLE_TASK_STK_SIZE在os_cfg_app.h这个头文件定义,大小为128
    在这里插入图片描述

  • CPU_STK * const OSCfg_IdleTaskStkBasePtr = (CPU_STK *)&OSCfg_IdleTaskStk[0];
    空闲任务的栈的起始地址和大小均被定义成一个常量,不能被修改。
    变量OSCfg_IdleTaskStkBasePtr和OSCfg_IdleTaskStkSize同时还在os.h中声明,这样就具有全局属性, 可以在其他文件里面被使用
    在这里插入图片描述

3、定义空闲任务TCB

任务控制块TCB是每一个任务必须的,空闲任务的TCB在os.h中定义,是一个全局变量

在这里插入图片描述

4、定义空闲任务函数

空闲任务正如其名,空闲,任务体里面只是对全局变量OSIdleTaskCtr ++ 操作

/* 空闲任务 */
void  OS_IdleTask (void  *p_arg)
{p_arg = p_arg;/* 空闲任务什么都不做,只对全局变量OSIdleTaskCtr ++ 操作 */for(;;){OSIdleTaskCtr++;}
}

全局变量OSIdleTaskCtr在os.h中定义
在这里插入图片描述

OS_IDLE_CTR是在os_type.h中重新定义的数据类型
在这里插入图片描述

5、空闲任务初始化

空闲任务的初始化在OSInit()在完成,意味着在系统还没有启动之前空闲任务就已经创建好,具体在os_core.c定义

/* RTOS初始化
** 初始化全局变量
*/
void OSInit (OS_ERR *p_err)
{/* 配置OS初始状态为停止态 */OSRunning =  OS_STATE_OS_STOPPED;/* 初始化两个全局TCB,这两个TCB用于任务切换 */OSTCBCurPtr = (OS_TCB *)0;OSTCBHighRdyPtr = (OS_TCB *)0;/* 初始化就绪列表 */OS_RdyListInit();/* 初始化空闲任务 */OS_IdleTaskInit(p_err);if (*p_err != OS_ERR_NONE) {return;}
}

OS_RdyListInit() 就绪列表初始化函数如下

/* 就绪列表初始化 */
void OS_RdyListInit(void)
{OS_PRIO i;OS_RDY_LIST *p_rdy_list;for( i=0u; i<OS_CFG_PRIO_MAX; i++ ){p_rdy_list = &OSRdyList[i];p_rdy_list->HeadPtr = (OS_TCB *)0;p_rdy_list->TailPtr = (OS_TCB *)0;}
}

OS_IdleTaskInit() 空闲任务初始化函数在OSInit()中调用,在系统还没有启动之前就被创建。
OS_IdleTaskInit() 函数如下:

/* 空闲任务初始化 */
void  OS_IdleTaskInit(OS_ERR  *p_err)
{	/* 初始化空闲任务计数器 */OSIdleTaskCtr = (OS_IDLE_CTR)0;/* 创建空闲任务 */OSTaskCreate( (OS_TCB     *)&OSIdleTaskTCB, (OS_TASK_PTR )OS_IdleTask, (void       *)0,(CPU_STK    *)OSCfg_IdleTaskStkBasePtr,(CPU_STK_SIZE)OSCfg_IdleTaskStkSize,(OS_ERR     *)p_err );
}
由于编译顺序,os_core.c中函数的顺序如下:/* 就绪列表初始化 */
void OS_RdyListInit(void)/* 空闲任务 */
void  OS_IdleTask (void  *p_arg)/* 空闲任务初始化 */
void  OS_IdleTaskInit(OS_ERR  *p_err)/* RTOS初始化 初始化全局变量 */
void OSInit (OS_ERR *p_err)/* 启动RTOS,将不再返回 */
void OSStart (OS_ERR *p_err)/* 任务切换,实际就是触发PendSV异常,然后在PendSV异常中进行上下文切换 */
void OSSched (void)

十九、UCOSIII:实现阻塞延时

阻塞延时的阻塞是指任务调用该延时函数后,任务会被剥离CPU使用权,然后进入阻塞状态,直到延时结束, 任务重新获取CPU使用权才可以继续运行。
在任务阻塞的这段时间,CPU可以去执行其他的任务, 如果其他的任务也在延时状态,那么CPU就将运行空闲任务。

1、阻塞延时函数

阻塞延时函数在os_time.c中定义

/* 阻塞延时 */
void  OSTimeDly(OS_TICK dly)
{/* 设置延时时间 */OSTCBCurPtr->TaskDelayTicks = dly;/* 进行任务调度 */OSSched();	//此处调度和前面不太一样,改动看下文
}

在os.h中声明

/* ================================================================================================================== */
/*                                                 TIME MANAGEMENT                                                    */
/* ================================================================================================================== */				   
void          OSTimeTick                (void);	
void          OSTimeDly                 (OS_TICK dly);

2、记录任务需要延时的时间

TaskDelayTicks是任务控制块的一个成员,用于记录任务需要延时的时间,单位为SysTick的中断周期。
比如我们本章当中SysTick的中断周期为10ms,调用OSTimeDly(2)则完成2*10ms的延时。
TaskDelayTicks被定义在os.h

/*
------------------------------------------------------------------------------------------------------------------------
*                                                   任务控制块
------------------------------------------------------------------------------------------------------------------------
*/
struct os_tcb
{CPU_STK         *StkPtr;CPU_STK_SIZE    StkSize;/* 任务延时周期个数 */OS_TICK         TaskDelayTicks;
};

3、任务切换的部分修改

OSSched(); 此处调度和前面不太一样,改动看下文

/* 任务切换,实际就是触发PendSV异常,然后在PendSV异常中进行上下文切换 */
void OSSched(void)
{
#if 0	/* 非常简单的任务调度:两个任务轮流执行 */if( OSTCBCurPtr == OSRdyList[0].HeadPtr ){OSTCBHighRdyPtr = OSRdyList[1].HeadPtr;}else{OSTCBHighRdyPtr = OSRdyList[0].HeadPtr;}
#endif/* 如果当前任务是空闲任务,那么就去尝试执行任务1或者任务2,看看他们的延时时间是否结束如果任务的延时时间均没有到期,那就返回继续执行空闲任务 */if( OSTCBCurPtr == &OSIdleTaskTCB ){if(OSRdyList[0].HeadPtr->TaskDelayTicks == 0){OSTCBHighRdyPtr = OSRdyList[0].HeadPtr;}else if(OSRdyList[1].HeadPtr->TaskDelayTicks == 0){OSTCBHighRdyPtr = OSRdyList[1].HeadPtr;}else{return;		/* 任务延时均没有到期则返回,继续执行空闲任务 */} }else{/*如果是task1或者task2的话,检查下另外一个任务,如果另外的任务不在延时中,就切换到该任务否则,判断下当前任务是否应该进入延时状态,如果是的话,就切换到空闲任务。否则就不进行任何切换 */if(OSTCBCurPtr == OSRdyList[0].HeadPtr){if(OSRdyList[1].HeadPtr->TaskDelayTicks == 0){OSTCBHighRdyPtr = OSRdyList[1].HeadPtr;}else if(OSTCBCurPtr->TaskDelayTicks != 0){OSTCBHighRdyPtr = &OSIdleTaskTCB;}else {return;		/* 返回,不进行切换,因为两个任务都处于延时中 */}}else if(OSTCBCurPtr == OSRdyList[1].HeadPtr){if(OSRdyList[0].HeadPtr->TaskDelayTicks == 0){OSTCBHighRdyPtr = OSRdyList[0].HeadPtr;}else if(OSTCBCurPtr->TaskDelayTicks != 0){OSTCBHighRdyPtr = &OSIdleTaskTCB;}else {return;		/* 返回,不进行切换,因为两个任务都处于延时中 */}}}/* 任务切换 */OS_TASK_SW();
}

二十、UCOSIII:修改main()函数

1、程序代码

/*
************************************************************************************************************************
*                                                    main函数
************************************************************************************************************************
*/
/*
* 注意事项:1、该工程使用软件仿真,debug需选择 Ude Simulator
*           2、在Target选项卡里面把晶振Xtal(Mhz)的值改为25,默认是12,
*              改成25是为了跟system_ARMCM3.c中定义的__SYSTEM_CLOCK相同,确保仿真的时候时钟一致
*/
int main(void)
{OS_ERR err;/* 关闭中断 */CPU_IntDis();/* 配置SysTick 10ms 中断一次 */OS_CPU_SysTickInit (10);/* 初始化相关的全局变量 */OSInit(&err);/* 创建任务 */OSTaskCreate ((OS_TCB*)      &Task1TCB,(OS_TASK_PTR ) Task1,(void *)       0,(CPU_STK*)     &Task1Stk[0],(CPU_STK_SIZE) TASK1_STK_SIZE,(OS_ERR *)     &err);OSTaskCreate ((OS_TCB*)      &Task2TCB,(OS_TASK_PTR ) Task2,(void *)       0,(CPU_STK*)     &Task2Stk[0],(CPU_STK_SIZE) TASK2_STK_SIZE,(OS_ERR *)     &err);/* 将任务加入到就绪列表 */OSRdyList[0].HeadPtr = &Task1TCB;OSRdyList[1].HeadPtr = &Task2TCB;/* 启动OS,将不再返回 */OSStart(&err);
}/*
************************************************************************************************************************
*                                                    函数实现
************************************************************************************************************************
*/
/* 软件延时 
void delay (volatile uint32_t count)
{for(; count!=0; count--);
}
*//* 任务1 */
void Task1( void *p_arg )
{for ( ;; ) {flag1 = 1;//delay( 100 );OSTimeDly(2);				//延时函数均替代为阻塞延时,延时时间均为2个SysTick中断周期,即20ms。flag1 = 0;//delay( 100 );OSTimeDly(2);/* 任务切换,这里是手动切换 *///OSSched();}
}/* 任务2 */
void Task2( void *p_arg )
{for ( ;; ) {flag2 = 1;//delay( 100 );OSTimeDly(2);//延时函数均替代为阻塞延时,延时时间均为2个SysTick中断周期,即20ms。flag2 = 0;//delay( 100 );OSTimeDly(2);/* 任务切换,这里是手动切换 *///OSSched();}
}

主要改动这些位置:
在这里插入图片描述
在这里插入图片描述

2、编译调试

逻辑分析仪中可看到两个任务的波形是完全同步,就好像CPU在同时干两件事情
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/723038.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CSS字体样式值,前端开发基础学习

元素特点&#xff1a; 块状元素&#xff1a; 在页面中以矩形区域显示。自上而下排列&#xff0c;独占一行可以直接添加宽高一般情况下&#xff0c;作为其他元素或内容的容器 行内元素&#xff1a; 在页面中最小单位也是矩形。在一行内逐个排列。不可以直接添加宽高&#xf…

OWASP Top 10 网络安全10大漏洞——A01:2021-访问控制中断

10大Web应用程序安全风险 2021年top10中有三个新类别、四个类别的命名和范围变化&#xff0c;以及一些合并。 A01&#xff1a;2021-访问控制中断 从第五位上升到top1&#xff0c;94%的应用程序都经过了某种形式的访问控制破坏测试&#xff0c;平均发生率为 3.81%且在贡献的…

flutter弹窗输入,Android学习的三个终极问题及学习路线规划

题库非常全面包括&#xff1a; Android基础知识: 基本涵盖Android所有知识体系&#xff0c;四大组件&#xff0c;Fragment,WebView,事件分发&#xff0c;View绘制…Java基础知识&高阶知识点: 基础部分不谈了&#xff0c;高阶部分&#xff1a;泛型&#xff0c;反射&#xff…

蓝桥杯刷题(一)

一、 import os import sys def dps(s):dp [0] * len(s)dp[0] ord(s[0]) - 96if len(s) 1:return dp[-1]dp[1] max(ord(s[0]) - 96, ord(s[1]) - 96)for i in range(2, len(s)):dp[i] max(dp[i - 1], dp[i - 2] (ord(s[i])) - 96)return dp[-1] s input() print(dps(s))…

【SpringBoot3.x教程 01】SpringBoot简介及工程搭建

前言&#xff1a;什么是SpringBoot&#xff1f; SpringBoot是一个开源的Java基础框架&#xff0c;它被设计来简化Spring应用的初始搭建以及开发过程。这个框架利用了“约定优于配置”的理念&#xff0c;提供了一系列大型项目中常用的默认配置&#xff0c;让开发者可以快速启动和…

stm32学习笔记:I2C通信外设原理(未完)

软件实现和硬件实现 串口通信为异步时序&#xff0c;用软件实现很麻烦&#xff0c;基本上用硬件实现 而I2C协议通信为同步时序&#xff0c;软件实现简单且灵活&#xff0c;硬件实现比较麻烦&#xff0c;故软件比较常用 但I2C硬件实现功能比较大&#xff0c;执行效率高&#xff…

【数据分享】1984~2020年中国长时间序列逐年人造夜间灯光数据集

各位同学们好&#xff0c;今天和大伙儿分享的是1984~2020年中国长时间序列逐年人造夜间灯光数据集。如果大家有下载处理数据等方面的问题&#xff0c;您可以私信或评论。 张立贤, 任浙豪, 陈斌, 宫鹏, 付昊桓, 徐冰. (2021). 中国长时间序列逐年人造夜间灯光数据集&#xff08;…

大数据开发-Hadoop分布式集群搭建

大数据开发-Hadoop分布式集群搭建 文章目录 大数据开发-Hadoop分布式集群搭建环境准备Hadoop配置启动Hadoop集群Hadoop客户端节点Hadoop客户端节点 环境准备 JDK1.8Hadoop3.X三台服务器 主节点需要启动namenode、secondary namenode、resource manager三个进程 从节点需要启动…

42岁前TVB女星近况曝光,曾因山头靠不住被雪藏兼生意失败

自从2021年前TVB高层余咏珊倒台离巢后&#xff0c;大批「余派」被雪藏&#xff0c;随即跟着走人&#xff0c;今年42岁的「元老级是非精」梁嘉琪就是其中之一。 梁嘉琪在离巢后就重新签约有线做回老本行主持节目&#xff0c;去年3月又与森美、小仪主持商台903节目《早霸王》&…

Zynq—AD9238数据采集DDR3缓存千兆以太网发送实验(二)

Zynq—AD9238数据采集DDR3缓存千兆以太网发送实验&#xff08;前导&#xff09; Zynq—AD9238数据采集DDR3缓存千兆以太网发送实验&#xff08;一&#xff09; Zynq—AD9238数据采集DDR3缓存千兆以太网发送实验&#xff08;三&#xff09; 五、实验目的 本次实验使用电脑上的…

动态规划(算法竞赛、蓝桥杯)--背包DP求具体方案

1、B站视频链接&#xff1a;E20 背包DP 求具体方案_哔哩哔哩_bilibili #include <bits/stdc.h> using namespace std; const int N1010; int v[N],w[N]; int f[N][N],p[N][N];int main(){int n,m;cin>>n>>m;for(int i1;i<n;i)cin>>v[i]>>w[i…

mybatis的xml文件如何配置能被识别

为了让MyBatis能够识别和使用XML Mapper文件&#xff0c;你需要确保这些文件被正确放置和配置。下面是确保MyBatis XML Mapper文件被识别的步骤&#xff1a; 1. 正确放置XML Mapper文件 通常&#xff0c;XML Mapper文件应该放在src/main/resources目录下。为了更好的组织这些…

基于SSM的农业信息管理系统的设计与实现(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的农业信息管理系统的设计与实现&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;…

字节跳动热门的前端开源项目

字节跳动开源官网 Arco Dsign Arco Design 是一套设计系统&#xff0c;主要服务于字节跳动旗下中后台产品的体验设计和技术实现。它的目标在于帮助设计师与开发者解放双手、提升工作效率&#xff0c;并高质量地打造符合业务规范的中后台应用。它拥有系统的设计规范和资源&…

运维知识点-hibernate引擎-HQL

HQL有两个主要含义&#xff0c;分别是&#xff1a; HQL&#xff08;Hibernate Query Language&#xff09;是Hibernate查询语言的缩写&#xff0c;它是一种面向对象的查询语言&#xff0c;类似于SQL&#xff0c;但不是去对表和列进行操作&#xff0c;而是面向对象和它们的属性…

ArmSoM Rockchip系列产品 通用教程 之 UART 使用

1. UART 简介​ Rockchip UART (Universal Asynchronous Receiver/Transmitter) 基于16550A串口标准&#xff0c;完整模块支持以下功能&#xff1a; 支持5、6、7、8 bits数据位。支持1、1.5、2 bits停止位。支持奇校验和偶校验&#xff0c;不支持mark校验和space校验。支持接…

Yolov8有效涨点,添加多种注意力机制,修改损失函数提高目标检测准确率

目录 简介 CBAM注意力机制原理及代码实现 原理 代码实现 GAM注意力机制 原理 代码实现 修改损失函数 YAML文件 完整代码 &#x1f680;&#x1f680;&#x1f680;订阅专栏&#xff0c;更新及时查看不迷路&#x1f680;&#x1f680;&#x1f680; http://t.csdnimg.c…

Mol2文件处理-拆分、合并、提取名称、计数与格式转换

欢迎浏览我的CSND博客&#xff01; Blockbuater_drug …点击进入 文章目录 前言一、Mol2文件合并二、Mol2文件拆分为含有单个分子的文件三、Mol2文件分子名称修改与提取3.1 分子名称修改去除空格3.2 文件名称提取 四、Mol2文件包含分子计数4.1 Mol2文件中分子计数4.2 分子计数传…

Python——与Matlab对应的Python版本

参考资料&#xff1a; Python——与Matlab对应的Python版本

Rust 开发的高性能 Python 包管理工具,可替换 pip、pip-tools 和 virtualenv

最近&#xff0c;我在 Python 潮流周刊 中分享了一个超级火爆的项目&#xff0c;这还不到一个月&#xff0c;它在 Github 上已经拿下了 8K star 的亮眼成绩&#xff0c;可见其受欢迎程度极高&#xff01;国内还未见有更多消息&#xff0c;我趁着周末把一篇官方博客翻译出来了&a…