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

news2025/1/22 13:09:10

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


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


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

2024.03.05

  • 十八、UCOSIII:空闲任务
    • 1、阻塞延时与空闲任务介绍
    • 2、定义空闲任务栈
    • 3、定义空闲任务TCB
    • 4、定义空闲任务函数
    • 5、空闲任务初始化
  • 十九、UCOSIII:实现阻塞延时
    • 1、阻塞延时函数
    • 2、记录任务需要延时的时间
    • 3、任务切换的部分修改
    • 4、修改中断服务函数
  • 二十、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)
 /* RTOS初始化 初始化全局变量 */
void OSInit (OS_ERR *p_err)
 /* 启动RTOS,将不再返回 */
void OSStart (OS_ERR *p_err)
 /* 任务切换,实际就是触发PendSV异常,然后在PendSV异常中进行上下文切换 */
void OSSched (void)
 /* 空闲任务 */
void  OS_IdleTask (void  *p_arg)
 /* 空闲任务初始化 */
void  OS_IdleTaskInit(OS_ERR  *p_err)

由于编译顺序,我们需要在os.h文件添加 OS_IdleTaskInit() 和 OS_IdleTask 的声明

/* ------------------------------------------------ INTERNAL FUNCTIONS ---------------------------------------------- */

void          OS_IdleTask               (void                  *p_arg);

void          OS_IdleTaskInit           (OS_ERR                *p_err);			

十九、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();
}

4、修改中断服务函数

在os_cpu_c.c中添加 中断服务函数 SysTick_Handler

/* SysTick 中断服务函数 */
void SysTick_Handler(void)
{
    OSTimeTick();
}

时钟中断处理函数在每次时钟中断发生后必须调用该函数。uC/OS-III使用这个函数来更新延时时间。
OSTimeTick() 函数如下:

void  OSTimeTick (void)
{
	unsigned int i;

	/* 扫描就绪列表中所有任务的TaskDelayTicks,如果不为0,则减1 */
	for(i=0; i<OS_CFG_PRIO_MAX; i++)
	{
		if(OSRdyList[i].HeadPtr->TaskDelayTicks > 0)
		{
			OSRdyList[i].HeadPtr->TaskDelayTicks --;
		}
	}
	
	/* 任务调度 */
	OSSched();
}

同时在 os.h中声明一下
在这里插入图片描述

二十、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.coloradmin.cn/o/1495647.html

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

相关文章

uniapp小程序获取位置权限(不允许拒绝)

需求 小程序上如果需要一些定位功能&#xff0c;那么我们需要提前获取定位权限。我们页面的所有功能后续都需要在用户同意的前提下进行&#xff0c;所以一旦用户点了拒绝&#xff0c;我们应该给予提示&#xff0c;并让用于修改为允许。 实现 1.打开手机GPS 经过测试发现即使…

第102讲:MySQL多实例与Mycat分布式读写分离的架构实践

文章目录 1.Mycat读写分离分布式架构规划2.在两台服务器中搭建八个MySQL实例2.1.安装MySQL软件2.2.创建每个MySQL实例的数据目录并初始化2.3.准备每个实例的配置文件2.4.准备每个实例的启动脚本2.6启动每台机器的MySQL多实例2.7.为每个MySQL实例设置密码2.8.查看每个MySQL实例的…

2024三掌柜赠书活动第十三期:API安全技术与实战

目录 前言 API安全威胁与漏洞 API安全技术与实践 API安全实战案例 关于《API安全技术与实战》 编辑推荐 内容简介 作者简介 图书目录 书中前言/序言 《API安全技术与实战》全书速览 结束语 前言 随着互联网的快速发展和应用程序的广泛使用&#xff0c;API&#xff…

excel统计分析——正交设计

参考资料&#xff1a;生物统计学 单因素试验通常采用完全随机设计活动随机区组设计&#xff1b;两因素试验通常采用析因设计&#xff1b;多因素试验不考虑因素间的互作时&#xff0c;可以采用拉丁方设计或正交拉丁方设计&#xff1b;需要考虑因素间的互作时&#xff0c;析因设计…

手回科技:人生的“小雨伞”,能否撑起自己的增长路?

有道是一年之计在于春。新年伊始&#xff0c;多家券商发布研报表达了对2024年保险市场表现的观点。 比如&#xff0c;开源证券表示&#xff0c;政策组合拳带来beta催化&#xff0c;保险业务端和弹性占优&#xff1b;中国银行证券指出&#xff0c;2024年&#xff0c;保险行业景…

HarmonyOS应用开发-使用Local Emulator运行应用/服务(使用本地模拟器)

1、单击File > Settings > SDK&#xff0c;下拉框选择HarmonyOS&#xff0c;勾选并下载Platforms下的System-image和Tools下的Emulator资源。 点击ok&#xff0c;等待安装完成 2、单击菜单栏的Tools > Device Manager&#xff0c;在Local Emulator页签&#xff0c;…

百度给程序员发放京东购物卡,注册即送30元购物卡

活动真实有效&#xff1a; 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09;https://comate.baidu.com/?inviteCodeexf818mt 活动参与流程说明&#xff1a;点击下面的邀请链接进行登陆&#xff0c;注意一定要邀请链接&#xff0c;因为通过链接注册可以获…

300分钟吃透分布式缓存-20讲:Redis如何处理文件事件和时间事件?

Redis 事件驱动模型 事件驱动模型 Redis 是一个事件驱动程序&#xff0c;但和 Memcached 不同的是&#xff0c;Redis 并没有采用 libevent 或 libev 这些开源库&#xff0c;而是直接开发了一个新的事件循环组件。Redis 作者给出的理由是&#xff0c;尽量减少外部依赖&#xff…

【Java】关于ZooKeeper的原理以及一致性问题,协议和算法和ZooKeeper的理论知识和应用 场景

1. 目录 目录 1. 目录 2. 什么是ZooKeeper 3. 一致性问题 4. 一致性协议和算法 4.1. 2PC&#xff08;两阶段提交&#xff09; 4.2. 3PC&#xff08;三阶段提交&#xff09; 4.3. Paxos 算法 4.3.1. prepare 阶段 4.3.2. accept 阶段 4.3.3. paxos 算法的死循环…

2024年阿里云2核4G服务器租用价格_2核4G性能测评_支持人数

阿里云2核4G服务器多少钱一年&#xff1f;2核4G配置1个月多少钱&#xff1f;2核4G服务器30元3个月、轻量应用服务器2核4G4M带宽165元一年、企业用户2核4G5M带宽199元一年。可以在阿里云CLUB中心查看 aliyun.club 当前最新2核4G服务器精准报价、优惠券和活动信息。 阿里云官方2…

JavaScript 入门手册(一)

目录 一、JavaScript 是什么? 1.1 JavaScript 介绍 1.2 JavaScript 与 ECMAScript 的关系 1.3 JavaScript 是脚本语言 1.4 JavaScript 的特点 1.5 运行 JavaScript 1.6 保留关键字 二、Node.js 是什么&#xff1f; 2.1 运行时是什么&#xff1f; 2.2 Node.js 的组成…

Ubuntu20.04安装并配置vscode

Ubuntu20.04安装并配置vscode vscode安装miniconda安装创建虚拟python3.8环境pytorch和匹配的cuda安装 vscode安装 VSCode可以通过 Snapcraft 商店或者微软源仓库中的一个 deb 软件包来安装。 我们这里选用安装VSCode snap版&#xff0c;打开你的终端(CtrlAltT)并且运行下面的…

LeetCode_25_困难_K个一组翻转链表

文章目录 1. 题目2. 思路及代码实现&#xff08;Python&#xff09;2.1 模拟 1. 题目 给你链表的头节点 h e a d head head &#xff0c;每 k k k 个节点一组进行翻转&#xff0c;请你返回修改后的链表。 k k k 是一个正整数&#xff0c;它的值小于或等于链表的长度。如果节…

VTK的编译和部署,配合c++和visual studio2022,VTK开发环境的配置

1.下载 在官网选择最新的版本 Download | VTK 下载之后进行解压&#xff0c;然后再里面创建build目录&#xff0c;方便后面使用cmake进行编译 2.对源码进行编译 打卡Cmake&#xff0c;如图操作 可以看到点击configure之后&#xff0c;cmake对我们的代码在进行处理 处理完成之…

openssl3.2 - exp - 产生随机数

文章目录 openssl3.2 - exp - 产生随机数概述笔记END openssl3.2 - exp - 产生随机数 概述 要用到openssl产生的随机数, 查了资料. 如果用命令行产生随机数, 如下: openssl rand -hex -num 6 48bfd3a64f54单步跟进去, 看到主要就是调用了一个RAND_bytes(), 没其他了. 官方说…

【vue.js】文档解读【day 2】 | 计算属性

如果阅读有疑问的话&#xff0c;欢迎评论或私信&#xff01;&#xff01; 本人会很热心的阐述自己的想法&#xff01;谢谢&#xff01;&#xff01;&#xff01; 文章目录 计算属性计算属性 vs 方法可计算属性Getter不应有副作用避免直接修改计算属性值 计算属性 我们已经学习…

基于SpringBoot+Vue+ElementUI+Mybatis前后端分离管理系统超详细教程(二)

学习后端CRUD操作 书接上文&#xff0c;我们学习了前后端分离项目的基础环境配置和用户管理模块的前后端基础搭建&#xff0c;以下链接是上一节教程内容详细步骤&#xff0c;友友们可以跟着步骤实操。本节课程我们在前面项目的基础上接着学习后端CRUD操作&#xff0c;真正打通数…

【你也能从零基础学会网站开发】Web建站之HTML+CSS入门篇 网站开发的基本概念与站点文件的管理

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;web开发者、设计师、技术分享 &#x1f40b; 希望大家多多支持, 我们一起学习和进步&#xff01;&#x1f604; &#x1f3c5; 如果对你有帮助的话&#xff0c;欢迎评论 &#x1f4ac;点赞&#x1f44d;&…

leetcode2

翻转链表 struct ListNode* reverseList(struct ListNode* head) {struct ListNode* prev NULL;struct ListNode* curr head;while (curr ! NULL) {struct ListNode* nextTemp curr->next;//nextTemp的作用是为了记录&#xff0c;以便再反转后可以curr->next prev; …

聚观早报 | ChatGPT新增朗读功能;vivo X Fold3细节曝光

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。 整理丨Cutie 3月6日消息 ChatGPT新增朗读功能 vivo X Fold3细节曝光 魅族21 PRO开启内测 Anthropic推出Claude 3系列 海底捞…