之前在ucos多任务切换中漏掉了一个变量,

OSCtxSwCtr标识系统任务切换次数

主要应该还是用在调试功能中

Ucos系统初始化函数为OSInit(),主要完成以下功能

全局变量初始化

就绪任务表初始化

空任务控制块初始化

事件控制块链表初始化

信号量集初始化

存储器管理初始化

Qs队列控制初始化

系统空闲任务初始化

系统统计任务初始化

部分功能需要依靠宏定义打开另外要注意一个变量OSTaskCtr标识系统全部任务数,在初始化完成之后就可以创建任务了,创建任务完成之后启动系统使用OSStart函数,代码如下

void  OSStart (void)

{

if (OSRunning == OS_FALSE) {

OS_SchedNew();

OSPrioCur     = OSPrioHighRdy;

OSTCBHighRdy  = OSTCBPrioTbl[OSPrioHighRdy];

OSTCBCur      = OSTCBHighRdy;

OSStartHighRdy();

}

}

开始阶段没有直接调用OS_SchedNew,因为此时系统是没有任务在执行的,也就没有中断锁啦,所以这一点需要注意,在系统启动之前,最好只留下系统中断,启动之后再打开中断,否则可能会造成问题

然后依旧是获取优先级,获取tcb,最后根据当前最高优先级任务调用OSStartHighRdy函数,该函数是一个需要汇编语言移植的函数,处于os_cpu_a.asm中,代码如下

OSStartHighRdy

LDR     R4, =NVIC_SYSPRI2      ; set the PendSV exception priority

LDR     R5, =NVIC_PENDSV_PRI

STR     R5, [R4]

MOV     R4, #0                 ; set the PSP to 0 for initial context switch call

MSR     PSP, R4

LDR     R4, =OSRunning         ; OSRunning = TRUE

MOV     R5, #1

STRB    R5, [R4]

;切换到最高优先级的任务

LDR     R4, =NVIC_INT_CTRL     ;rigger the PendSV exception (causes context switch)

LDR     R5, =NVIC_PENDSVSET

STR     R5, [R4]

CPSIE   I                      ;enable interrupts at processor level

OSStartHang

B       OSStartHang            ;should never get here死循环

先将 堆栈清零,然后将OSRunning设置为true,最后触发中断,因为之前的OS_SchedNew已经得到了最高优先级的任务,所以触发中断之后,在中断中就能直接切换到我们想要切换的最高优先级任务中,实现系统启动

另外需要注意一点,如果使用了统计任务,那么系统开始的时候必须要启动统计任务,否则打开这个宏却没有初始化统计任务会在成一定的异常

关于系统临界段

在系统运行过程中,有时候某段代码是不能被打断的,而中断的时机经常会比较随机,为了解决这个问题,提出了临界段的概念,ucos一般采用三种方式来处理临界段

  1. 开关中断的方式
  2. 通过保存程序状态字并关中断的方式
  3. 保存程序状态字到cpu_sr变量中

第一种方法简单粗暴,第二种方法复杂一点,但是可以让处理器中断允许标志在中断前和中断之后发生变化,但是状态时压到堆栈中的第三种方式使用局部变量来保存中断状态字,不用使用堆栈,更加灵活

移植的时候可以任选一种方式,一般选择第三种方式,示例如下

OS_CPU_SR_Save

MRS     R0, PRIMASK    ;读取PRIMASK到R0,R0为返回值

CPSID   I             ;PRIMASK=1,关中断(NMI和硬件FAULT可以响应)

BX      LR              ;返回

OS_CPU_SR_Restore

MSR     PRIMASK, R0    ;读取R0到PRIMASK中,R0为参数

BX      LR             ;返回

#if OS_CRITICAL_METHOD == 3

#define  OS_ENTER_CRITICAL()  {cpu_sr = OS_CPU_SR_Save();}

#define  OS_EXIT_CRITICAL()   {OS_CPU_SR_Restore(cpu_sr);}

#endif

Ucos时钟

Ucos为了处理等待,延时等与时间有关的时间,引入了一个周期性的信号,也就是ucos时钟,该时钟依托于硬件环境,需要我们根据硬件处理器的定时来去确定,与之相关的宏有一个,如下

OS_TICKS_PER_SEC,该宏定义了系统1s类中断的次数,例如我们将该宏定义为1000,那么我们就要保证系统每1ms中断一次,并且在中断处理程序中调用如下代码

OSIntEnter();     //进入中断

OSTimeTick();       //调用ucos的时钟服务程序

OSIntExit();        //触发任务切换软中断

OSIntEnter和OSIntExit之前已经说过了,来看看OSTimeTick的构成,如下

while (ptcb->OSTCBPrio != OS_TASK_IDLE_PRIO) {

OS_ENTER_CRITICAL();

if (ptcb->OSTCBDly != 0u) {

ptcb->OSTCBDly--;

if (ptcb->OSTCBDly == 0u) {

if ((ptcb->OSTCBStat & OS_STAT_PEND_ANY) != OS_STAT_RDY) {

ptcb->OSTCBStat  &= (INT8U)~(INT8U)OS_STAT_PEND_ANY;

ptcb->OSTCBStatPend = OS_STAT_PEND_TO;

} else {

ptcb->OSTCBStatPend = OS_STAT_PEND_OK;

}

if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) {

OSRdyGrp               |= ptcb->OSTCBBitY;

OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;

}

}

}

ptcb = ptcb->OSTCBNext;

OS_EXIT_CRITICAL();

}

可以看到,在这个函数中,系统遍历了整个tcb控制结构,对每一个元素中的OSTCBDly元素进行递减,当某个任务控制块的延时时间OSTCBDly为0的时候,检测任务的状态是否为挂起状态,如果不是挂起状态,就修改系统就绪表将当前任务设置为reday,等待系统进行任务调度,这个任务调度就是在上一个三句代码中的最后一句OSIntExit()完成的,这也是为什么设计一个中断中切换任务功能的原因,这样可以保证机时某个任务不释放处理器,在出现更高优先级的任务的时候也能立即切换到该任务中.

为了不让系统中优先级最高的任务独占处理器,ucos设计了一个延时函数,用于高优先级任务主动释放掉cpu所有权,在实际的嵌入式系统中,这种释放也是很常见的,比如等待器件反应,人眼视觉残留等都需要,与之相关的重要函数是

OSTimeDly 参数是延时节拍数

OSTimeDlyHMSM 长时间延时,参数分别为延时小时 分 秒 毫秒

OSTimeDlyResume 取消特定优先级的任务的延时

OSTimeGet 获取当前系统节拍

OSTimeSet 设置当前系统节拍

基本上我们只要关注OSTimeDly和OSTimeDlyResume便好,先看OSTimeDly

if (OSIntNesting > 0u) {

return;

}

if (OSLockNesting > 0u) {

return;

}

if (ticks > 0u) {

OS_ENTER_CRITICAL();

y            =  OSTCBCur->OSTCBY;

OSRdyTbl[y] &= (OS_PRIO)~OSTCBCur->OSTCBBitX;

if (OSRdyTbl[y] == 0u) {

OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY;

}

OSTCBCur->OSTCBDly = ticks;

OS_EXIT_CRITICAL();

OS_Sched();

当设置的延时节拍大于0的时候,首先取消当前任务的在系统就绪表中的就绪标志,然后将系统控制块的OSTCBDly参数设置为设置的节拍数,最后调用系统任务调度函数,完成系统任务调度,并且OSTCBDly设置之后和之前的中断处理OSTimeTick函数就关联起来了,从而实现系统延时

取消任务的延时函数为OSTimeDlyResume,有用的代码为

ptcb = OSTCBPrioTbl[prio];

*******

ptcb->OSTCBDly = 0u;

if ((ptcb->OSTCBStat & OS_STAT_PEND_ANY) != OS_STAT_RDY) {

ptcb->OSTCBStat     &= ~OS_STAT_PEND_ANY;

ptcb->OSTCBStatPend  =  OS_STAT_PEND_TO;

} else {

ptcb->OSTCBStatPend  =  OS_STAT_PEND_OK;

}

if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) {

OSRdyGrp               |= ptcb->OSTCBBitY;

OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;

OS_EXIT_CRITICAL();

OS_Sched();

} else {

OS_EXIT_CRITICAL();

}

首先获取想要取消延时的任务tcb(根据优先级获取),然后查看任务是否被挂起,如果没被挂起而且任务就绪,就设置任务就绪表相关位置为raday,并调用OS_Sched进行任务切换,但是并不是说取消了一定会运行,还是要看任务优先级的.

到这里我们可以说任务的调度时机在于系统定时中断的时候和系统调用延时函数的时候.(后面还有别的延时时机).

ucos系统初始化及启动过程的更多相关文章

  1. Android 面试必备 - 系统、App、Activity 启动过程“一锅端”

    Android 系统启动过程 从系统层看: linux 系统层 Android系统服务层 Zygote 从开机启动到Home Launcher: 启动bootloader (小程序:初始化硬件) 加载 ...

  2. 走进Linux之systemd启动过程

    Linux系统的启动方式有点复杂,而且总是有需要优化的地方.传统的Linux系统启动过程主要由著名的init进程(也被称为SysV init启动系统)处理,而基于init的启动系统被认为有效率不足的问 ...

  3. Android 启动过程总结

    SystemServer的启动 frameworks/base/services/java/com/android/server/SystemServer.java: run() 其中调用Activi ...

  4. spark 源码分析之四 -- TaskScheduler的创建和启动过程

    在 spark 源码分析之二 -- SparkContext 的初始化过程 中,第 14 步 和 16 步分别描述了 TaskScheduler的 初始化 和 启动过程. 话分两头,先说 TaskSc ...

  5. Hadoop源码:namenode格式化和启动过程实现

    body { margin: 0 auto; font: 13px / 1 Helvetica, Arial, sans-serif; color: rgba(68, 68, 68, 1); padd ...

  6. 关于esp32的系统初始化启动过程及设计学习方法

    对于esp32,其开发程序中有且只能有一个app_main函数,该函数是用户程序的入口,这在没有调用FreeRTOS的系统中相当于函数main,但其实在app_main之前,系统还有一段初始化的过程, ...

  7. 详解linux系统的启动过程及系统初始化

    一.linux系统的启动流程 关于linux系统的启动流程我们可以按步进行划分为如下: POST加电自检 -->BIOS(Boot Sequence)-->加载对应引导上的MBR(boot ...

  8. 探索 Linux 系统的启动过程

    引言 之所以想到写这些东西,那是因为我确实想让大家也和我一样,把 Linux 桌面系统打造成真真正正日常使用的工具,而不是安装之后试用几把再删掉.我是真的在日常生活和工作中都使用 Linux,比如在 ...

  9. Android系统默认Home应用程序(Launcher)的启动过程源代码分析

    在前面一篇文章中,我们分析了Android系统在启动时安装应用程序的过程,这些应用程序安装好之后,还需要有一个 Home应用程序来负责把它们在桌面上展示出来,在Android系统中,这个默认的Home ...

随机推荐

  1. 编译Android各种错误

    第一次编译成功,第二次出现Value for 'keystore' is not valid. It must resolve to a single path 打开proj.android\ant. ...

  2. static加载问题

    原文地址:http://blog.csdn.net/lubiaopan/article/details/4802430     感谢原作者! static{}(即static块),会在类被加载的时候执 ...

  3. 让横向ul在页面中水平居中的方法

    在导航的布局中,导航条会用横向布局的ul li.如果要让其居中,怎么办呢? 第一种方法: ul{text-align:center;} li{display:inline} 这种方法不适合ie低版本. ...

  4. Linux学习 -- Shell编程 -- 条件判断

    按照文件类型进行判断 两种格式 test -e /root/install.log [ -e /root/install.log ]   注意空格  适合用于脚本中 echo $?可以看到结果 [ - ...

  5. 转:Selenium2.0之grid学习总结

    (一)介绍: Grid的功能: 并行执行 通过一个中央管理器统一控制用例在不同环境.不同浏览器下运行 灵活添加变动测试机 (二)快速开始 这个例子将介绍如何使用selenium2.0的grid,并且注 ...

  6. Dev之ChartControl控件(二)— 绘制多重坐标图形

    有时针对一个ChartControl控件可能要设置多个Y轴,进行显示: 以下举个例子:如在一个Chart中显示多个指标项如图: 首先,读取数据,并对左边的Y轴最大和最小值进行设定 IndexSerie ...

  7. java输出日期时间

    Calendar类下方法 c.add(Calendar.YEAR,4);//加4年 c.add(Calendar.MONTH,-1);// 月份减1 c.set(2012,2,23); //把时间设置 ...

  8. SQL Server 2008登录问题(错误 233和18456)解决方法

    今天使用 SQLSERVER2008 先遇到了233 错误,后又遇到了 18456 ,从网上找到了解决方法,具体如下: 问题一 : 已成功与服务器建立连接,但是在登录过程中发生错取.(provider ...

  9. javascript中的正则匹配函数exec(),test(),match()

    test() var str = "cat";var reStr = /cat/;alert(reStr.test(str)); 输出为:true 它的返回值为true or fa ...

  10. Android----基于多触控的图片缩放和拖动代码实现

    引自:http://www.codefans.net/articles/584.shtml 一个android中自定义的ImageView控制,可对图片进行多点触控缩放和拖动类,包括了对图片放大和图片 ...