下面这几句话也是在网络上看到,感觉写的很通俗易懂供参考:
任务状态
简单分为运行态,就绪态,阻塞态。
运行态:万事俱备,不欠东风(获得CPU控制权);
就绪态:万事俱备,只欠东风(缺少CPU控制权);
阻塞态:万事不俱备(等事件或信号),还欠东风(缺少CPU控制权);
(运行态:老板签过字、银行正常上班有钱------可以正常发薪水)
(就绪态:老板没签字、银行正常上班有钱 ----- 还需要等待)
(阻塞态:老板没签字、银行正常上班没钱 ----- 还需要等待)
每个任务基本上都会游离于这三种状态。
运行到阻塞,就绪到运行称为任务切换过程。
从用户的角度看,UCOSIII的任务一共有5种状态:
1、休眠态:
任务已经在CPU的flash中了,
但是还不受UCOSIII管理。
2、就绪态:
系统为任务分配了任务控制块,
并且任务已经在就绪表中登记,
这时这个任务就具有了运行的条件,
但是没有获得CPU 的使用权
此时任务的状态就是就绪态。
3、运行态:
任务获得CPU的使用权,正在运行。
4、等待态:
正在运行的任务需要等待一段时间,
或者等待某个事件,
这个任务就进入了等待态,
此时系统就会把CPU使用权转交给别的任务。
5、中断服务态:
当发送中断,
当前正在运行的任务会被挂起,
CPU转而去执行中断服务函数,此时任务的任务状态叫做中断服务态。
白话任务堆栈、任务控制块、任务函数
在多任务操作系统中创建任务时,都需要指定该任务的堆栈大小,
那么这个堆栈的作用时什么呢?
什么情况下需要用到堆栈,以及大小不够时会产生什么异常呢?
任务堆栈的作用:
1 任务处于运行状态:
当任务在运行时,
一般都会调用各式各样的函数,
而函数的局部变量,参数,返回值是存在于函数栈帧里的,
每个函数都拥有独立的栈帧,
各个栈帧使用的空间就是任务堆栈的空间。
所以任务堆栈的作用是用于保存函数在运行/调用过程中的参数/局部变量。
(理解堆栈就是个仓库仓库里各种各样的商品也就是各种功能不同函数)
2 任务处于切换
当运行的任务被切换时,需要保护现场(CPU中寄存器的值),
以便于下次恢复数据。
所以任务堆栈的作用是用于保存CPU中寄存器的值。
3
任务(低优先级的)在运行过程中,
随时可能被切换,
所以CPU中寄存器的值入栈的栈位置是不确定的,
这取决于当前任务的执行情况。
4 堆栈溢出
若堆栈的空间设置太大,会浪费内存资源。
而设置得太小,则会出现堆栈溢出,在没有MMU功能的操作系统中,
可能会导致系统奔溃。
所以,
需要根据任务的情况设置合适的堆栈大小。
同时,应避免使用递归调用函数,
函数中局部变量的分配空间不能太大。
任务堆栈是任务的重要部分,
堆栈是在RAM中按照“先进先出(FIFO)”的原则
组织的一块连续的存储空间。
为了满足任务切换和响应中断时保存CPU寄存器中的内容及
任务调用其它函数时的需要,
每个任务都应该有自己的堆栈。
一般是这样定义的
#define START_STK_SIZE 512 //堆栈大小
CPU_STK START_TASK_STK[START_STK_SIZE];//定义一个数组来作为任务堆栈
一般就是这样定义的,
明白就行不能有压力。
任务堆栈的大小是多少呢?
CPU_STK为 CPU_INT32U类型,
也就是 unsigned int类型,
为4字节的,
那么任务堆栈
START_TASK_STK的大小就为:512 X 4=2048字节!
任务如何才能切换回上一个任务
并且还能接着从上次被中断的地方开始运行?
这一点很重要系统是如何来切换任务的?
它是怎么知道某一个任务运行到了那里?
它是怎么来记录任务运行过程中产生的数据?
这就是任务堆栈初始化的工作
这里是不是和刚学习单片机c51有些类似
org 0x0300
ljmp main
main: mov r0,r1
.....
.....
.....
.....
ajmp main
道理是一样的
只不过在C 中我们直接定义了几个大的ROM
每个ROM有是连续的存储空间
好似这样的结构
................
. c51 .
. .
. .
. void main() .
. .
. .
. .
................
........................................................
. stm32 . .
. ucos - iii . .
........................................................
. void main() . . . .
. .void main() . . .
. . .void main() . .
. . . . void main() .
........................................................
51 的ROM 空间有过2K 、16K、64K 的
STM32 的空间就大的多了
这样利用ucos iii 的组织能力就能在其内部分割出来
相同或不相同的 void main(); 来
这其实就是任务堆栈的原型了。
至于在单片机内部是如何分配的就不知道了。
知道堆栈的大概了那么
恢复现场就是重新读取保存下来的CPU的内部各个寄存器数据。
因此在创建一个新任务时,
必须把系统启动这个任务时所需的CPU各个寄存器初始值事先存放在任务堆栈中。
这样当任务获得CPU使用权时,
就把任务堆栈的内容复制到CPU的各个寄存器,
从而可以任务顺利地启动并运行。
把任务初始数据存放到任务堆栈的工作就叫做任务堆栈的初始化,
UCOSIII 提供了完成堆栈初始化的函数:
OSTaskStkInit()。
CPU_STK *OSTaskStkInit (OS_TASK_PTR p_task,
void *p_arg,
CPU_STK *p_stk_base,
CPU_STK *p_stk_limit,
CPU_STK_SIZE stk_size,
OS_OPT opt)
用户一般不会直接操作堆栈初始化函数,
任务堆栈初始化函数由任务创建函数OSTaskCreate()调用。
不同的CPU对于的寄存器和对堆栈的操作方式不同,
因此在移植UCOSIII的时候需要
用户根据各自所选的CPU来编写任务堆栈初始化函数。
前面我们创建了一个任务堆栈,怎么使用这个任务堆栈?
作为任务创建函数OSTaskCreate()的参数,
函数OSTaskCreate()如下:
void OSTaskCreate (OS_TCB *p_tcb,
CPU_CHAR *p_name,
OS_TASK_PTR p_task,
void *p_arg,
OS_PRIO prio,
CPU_STK *p_stk_base, //任务堆栈基地址
CPU_STK_SIZE stk_limit, //任务堆栈栈深
CPU_STK_SIZE stk_size, //任务堆栈大小
OS_MSG_QTY q_size,
OS_TICK time_quanta,
void *p_ext,
OS_OPT opt,
OS_ERR *p_err)
其实看着有些复杂,其实很多参数都是一定的;
学习过后就理解
基础东西很重要
特别是C 语言的基础知识和算法
因为基础的都是实际来处理具体问题的
即便上了系统
系统也只是起到一个调度的作用
平衡各个任务之间的运行
函数OSTaskCreate()中的参数p_stk_base如何确定?
根据堆栈的增长方式,
堆栈有两种增长方式:
向上增长:堆栈的增长方向从低地址向高地址增长。
向下增长:堆栈的增长方向从高地址向低地址增长
函数OSTaskCreate()中的参数p_stk_base是任务堆栈基地址,
那么如果CPU的堆栈是向上增长的话
那么基地址就&START_TASK_STK[0],
如果CPU堆栈是向下增长的话
基地址就是&START_TASK_STK[START_STK_SIZE-1]
STM32的堆栈是向下增长的!
写了很多废话,只是 为了了解任务堆栈
也写的没有趣味性了
失败
|