UCOS-II任务管理1

任务控制块:
  一旦任务建立了,任务控制块OS_TCBs将被赋值,任务控制块是一个数据结构当任务的CPU使用权限被剥夺时,uC/OS用它来保存该任务的状态。
typedef struct os_tcb
{
  OS_STK *OSTCBStkPtr;//指向任务栈顶的指针,
  #if OS_TASK_CREATE_EXT_EN
  void *OSTCBExtPtr;//指向用户定义的任务控制块扩展。
  OS_STK *OSTCBStkBottom;//指向任务栈底的指针
  //栈中可以容纳的指针元素数目而不是字节,标示栈容量的总数
  INT32U OSTCBStkSize;
  
  //选择项,OS_TASK_OPT_STK_CHK,OS_TASK_OPT_STK_CLR,OS_TASK_SAVE_FP
  INT16U OSTCBOpt;
  
  INT16U OSTCBId;//任务识别码
  #endif
  
  //用于任务控制块的双重链接
  struct os_tcb *OSTCBNext;
  struct os_tcb *OSTCBPrev;
  
  #if (OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_EN || OS_SEM_EN
  OS_EVENT *OSTCBEventPtr;//指向事件控制块的指针
  #endif
  
  #if (OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_EN
  void *OSTCBMsg;//指向传给任务消息的指针
  #endif
  
  INT16U OSTCBDly;//任务延时使用
  INT8U OSTCBStat;//任务状态字,为0表示任务进入就绪态。
  INT8U OSTCBPrio;//任务优先级
  
  //用于加速任务进入就绪态的过程或进入等待事件发生状态的过程,
  INT8U OSTCBX;
  INT8U OSTCBY;
  INT8U OSTCBBitX;
  INT8U OSTCBBitY;
  
  #if OS_TASK_DEL_EN
  BOOLEAN OSTCBDelReq;//表示该任务是否需要删除
  #endif
} OS_TCB;

任务控制块中几个成员的算法:
  OSTCBY = priority >> 3;
  OSTCBBitY = OSMapTbl[priority >> 3];
  OSTCBX = priority & 0x07;
  OSTCBBitX = OSMapTbl[priority & 0x07];

就绪表:
  每个任务被赋予不同的优先级等级,从 0 级到最低优先级OS_LOWEST_PR1O,包括 0 和OS_LOWEST_PR1O 在内。每个任务的就绪态标志都放入就绪表中的,就绪表中有两个变量 OSRedyGrp 和OSRdyTbl[]。
  
当 OSRdyTbl[0]中的任何一位是 1 时,OSRdyGrp 的第 0 位置 1,
当 OSRdyTbl[1]中的任何一位是 1 时,OSRdyGrp 的第 1 位置 1,
...
当 OSRdyTbl[6]中的任何一位是 1 时,OSRdyGrp 的第 6 位置 1,
当 OSRdyTbl[7]中的任何一位是 1 时,OSRdyGrp 的第 7 位置 1,

OSMapTbl[]的值:
  OSMapTbl[0]:0000 0001
  OSMapTbl[1]:0000 0010
  OSMapTbl[2]:0000 0100
  ...
  OSMapTbl[7]:1000 0000

使任务进入就绪态:
  OSRdyGrp |= OSMapTbl[prio >> 3];
  OSRdyTbl[prio >> 3] |= OSMapTbl[prio & 0x07];

从就绪表中删除一个任务:
  if ((OSRdyTbl[prio >> 3] &= ~OSMapTbl[prio & 0x07]) == 0)
  OSRdyGrp &= ~OSMapTbl[prio >> 3];


OSUnMapTbl[ ]:是预先存好的一个表,用于查询一个字节中最低位为1的位在第几bit。

找出进入就绪态的优先级最高的任务:
  y = OSUnMapTbl[OSRdyGrp];
  x = OSUnMapTbl[OSRdyTbl[y]];
  prio = (y << 3) + x;


任务调度:
  uC/OS任务调度所花费的时间是常数。
  任务级调度函数:OSSched();
  中断级调度函数:OSIntExt();

void OSSched (void)
{
  INT8U y;
  OS_ENTER_CRITICAL();
  if ((OSLockNesting | OSIntNesting) == 0)//判断中断嵌套层数和任务调度器是否上锁
  {
  y = OSUnMapTbl[OSRdyGrp];
  OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);
  if (OSPrioHighRdy != OSPrioCur)
   {
  OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
  OSCtxSwCtr++;
  OS_TASK_SW();
  }
  }
  OS_EXIT_CRITICAL();
}
任务切换的步骤:
将被挂起任务的微处理器寄存器推入堆栈,然后将较高优先级的任务的寄存器值从栈中恢复到寄存器中。
要将 OS_TCBHighRdy 指向即将被运行的任务,还需要让当前任务控制块 OSTCBCur 指向即将被运行的任务。


给任务调度器上锁和解锁:
  OSSchedlock()、 OSSchedUnlock()。 调用 OSSchedlock()的任务保持对 CPU 的控制权,尽管有个优先级更高的任务进入了就绪态。但是中断服务是能够被识别的(假设中断是打开的),OSLockNesting表示调度器上锁的嵌套层数,最多嵌套255层,为0时即不上锁。
  调用 OSSchedLock()以后,用户的应用程序不得使用任何能将现行任务挂起的系统调用。也就是说,用户程序不得调用OSMboxPend()、OSQPend()、OSSemPend()、OSTaskSuspend(OS_PR1O_SELF)、OSTimeDly()或 OSTimeDlyHMSM(),直到 OSLockNesting 回零为止。因为调度器上了锁,用户就锁住了系统,任何其它任务都不能运行。
  当低优先级的任务要发消息给多任务的邮箱、消息队列、信号量时,用户不希望高优先级的任务在邮箱、队列和信号量没有得到消息之前就取得了CPU 的控制权,此时,用户可以使用禁止调度器函数。


空闲任务:
  OSTaskIdle() 这个任务在没有其它任务进入就绪态时投入运行。这个空闲任务[OSTaskIdle()]永远设为最低优先级,空闲任务不可能被应用软件删除。闲任务OSTaskIdle()什么也不做,只是在不停地给一个 32 位的名叫 OSIdleCtr 的计数器加 1,统计任务使用这个计数器以确定现行应用软件实际消耗的 CPU 时间。


统计任务:
  OSTaskStat()  如果用户将系统定义常数 OS_TASK_STAT_EN(见文件 OS_CFG.H)设为 1,这个任务就会建立。一旦得到了允许,OSTaskStat()每秒钟运行一次(见文件 OS_CORE.C),计算当前的 CPU 利用率。 用百分比表示,这个值放在一个有符号 8 位整数 OSCPUsage 中,精读度是 1 个百分点。
  如果用户应用程序打算使用统计任务,用户必须在初始化时建立一个唯一的任务,在这个任务中调用 OSStatInit() 换句话说,在调用系统启动函数 OSStart()之前,用户初始代码必须先建立一个任务,在这个任务中调用系统统计初始化函数OSStatInit(),然后再建立应用程序中的其它任务。
  为了能够计算CPU的使用率,所以在OSStatInit()中主要任务就是得到在1S内能将OSIdleCtr加的最大次数并保存。
  
时钟节拍:
  μC/OS 需要用户提供周期性信号源,用于实现时间延时和确认超时。节拍率应在每秒10 次到 100 次之间,或者说 10 到 100Hz。时钟节拍率越高,系统的额外负荷就越重。时钟节拍的实际频率取决于用户应用程序的精度。时钟节拍源可以是专门的硬件定时器,也可以是来自 50/60Hz 交流电源的信号。
  用户必须在多任务系统启动以后再开启时钟节拍器,也就是在调用 OSStart()之后。换句话说,在调用 OSStart()之后做的第一件事是初始化定时器中断。千万不能再OSInit之后就允许时钟节拍中断, 时钟节拍中断有可能在μC/OS-Ⅱ启动第一个任务之前发生,此时μC/OS-Ⅱ是处在一种不确定的状态之中,用户应用程序有可能会崩溃。


OSInit() uC/OS初始化:
  在调用μC/OS-Ⅱ的任何其它服务之前,μC/OS-Ⅱ要求用户首先调用系统初始化函数OSIint()。OSIint()初始化μC/OS-Ⅱ所有的变量和数据结构。


OSStart() uC/OS启动:
  多任务的启动是用户通过调用 OSStart()实现的。然而,启动μC/OS-Ⅱ之前,用户至少要建立一个应用任务。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
抱歉,作为AI语言模型,我没有权限写代码,只能回答一些问题并提供一些相关的资料,以供参考。 UCOS-II是一款小型的可裁剪的实时操作系统,它提供了一种方式来组织和管理复杂的嵌入式系统。UCOS-II支持任务管理、信号量、消息队列、邮箱等通信机制,可以实现多任务并发执行,并提供了优先级调度和时间片轮转两种任务调度方式。 UCOS-II任务通信管理是通过信号量、消息队列、邮箱等来实现的。在任务中需要使用相应的通信机制进行同步或异步的数据交换。具体的实现方法可以参考UCOS-II的官方文档或者相关的书籍。 以下是参考代码: ``` /* 任务1 */ static void task1(void *p_arg) { OS_ERR err; CPU_INT08U buffer[10]; while (1) { /* 从消息队列中获取数据 */ OSQPend(&queue, 0, OS_OPT_PEND_BLOCKING, NULL, &err); /* 处理数据 */ handle_data(buffer); } } /* 任务2 */ static void task2(void *p_arg) { OS_ERR err; CPU_INT08U buffer[10]; while (1) { /* 等待信号量 */ OSSemPend(&semaphore, 0, OS_OPT_PEND_BLOCKING, NULL, &err); /* 发送数据到消息队列 */ OSQPost(&queue, buffer, sizeof(buffer), OS_OPT_POST_FIFO, &err); } } int main(void) { /* 初始化UCOS-II内核 */ OSInit(&err); /* 创建任务 */ OSTaskCreate(&task1_tcb, "Task 1", task1, NULL, TASK1_PRIORITY, task1_stack, TASK_STACK_SIZE, 0, 0, 0, 0, &err); OSTaskCreate(&task2_tcb, "Task 2", task2, NULL, TASK2_PRIORITY, task2_stack, TASK_STACK_SIZE, 0, 0, 0, 0, &err); /* 创建信号量和消息队列 */ OSSemCreate(&semaphore, "Sem", 0, &err); OSQCreate(&queue, "Queue", QUEUE_SIZE, &err); /* 启动UCOS-II */ OSStart(&err); return 0; } ``` 此外,UCOS-II还提供了一些与应用相关的服务,如时钟管理、内存管理、文件系统等。如果需要更加详细的资料,可以参考UCOS-II的官方文档或者相关的书籍。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值