跳到正文
HeZzz's Notes
返回

嵌入式操作系统-2025sp-回忆版

在 Github 上编辑此页

嵌入式操作系统 2025 春季学期的回忆版真题。

本文连载于嵌入式操作系统-2025sp-回忆版 | HeZzz.

答案来源于 GPT-5.5 和 NotebookLM,并由我校对,可能不完全准确,仅供参考。

🙇‍♂️🙇‍♂️🙇‍♂️时间仓促,有不足之处烦请及时告知。邮箱hez2z@foxmail.com 或者在 速通之家 群里 @9¾


一、简答题(5道 × 10分)

1. μC/OS-II 中的任务有哪五个状态?它们之间是如何相互转换的?

任务状态转换图


2. 如果系统想要取消优先级为 33 的任务,那么是怎么找到该任务在 OSRdyTbl 的具体位置?

  1. μC/OS-II 优先级由 6 位二进制数决定(最高支持 64 个优先级)。优先级 3333 转换为二进制数为 1000012100001_2(来源:课件第2章 P.40)

  2. 确定组号(行号):优先级的高 3 位表示任务所在的组号。计算算式为:

    Y=333=4(二进制为 1002)\text{Y} = 33 \gg 3 = 4 \quad (\text{二进制为 } 100_2)

    对应在就绪表中属于第 44 组,即映射至数组元素 OSRdyTbl[4](来源:课件第2章 P.40)

  3. 确定位号(列号):优先级的低 3 位表示任务在组内的具体位号。计算算式为:

    X=33 & 0x07=1(二进制为 0012)\text{X} = 33 \ \& \ 0x07 = 1 \quad (\text{二进制为 } 001_2)

    对应在 OSRdyTbl[4] 中的第 11 位(从第 0 位算起,屏蔽码对应 21=0x022^1 = 0x02)。(来源:课件第2章 P.40)

  4. 注销操作:若要从就绪表中清除该就绪状态,执行: OSRdyTbl[4] &= ~0x02;(即清除第 1 位)。若清除后该元素值变为了 0,则还需要同步清除 OSRdyGrp 的第 4 位:OSRdyGrp &= ~0x10;(来源:课件第2章 P.44)


3. 数组 OSTCBPrioTbl[] 的作用是什么?


4. OSCtxSw() 完成的主要工作有哪些?

OSCtxSw() 为汇编编写的内核任务切换执行体,主要工作依次为:

  1. 将被中止(当前运行)任务的断点指针 PC 压入该任务的专用堆栈。
  2. 将 CPU 的所有通用寄存器(如 PSW、通用累加器、变址寄存器等)压栈保存。
  3. 将被中止任务当前的堆栈指针 SP 写入其控制块的 OSTCBStkPtr 成员中。
  4. 执行 TCB 指针更新:OSTCBCur = OSTCBHighRdy,并且 OSPrioCur = OSPrioHighRdy
  5. 将系统的 SP 指针重定向到新运行任务的 OSTCBStkPtr 指向的地址。
  6. 从新任务的堆栈中弹出并恢复所有的 CPU 通用寄存器。
  7. 执行中断返回指令(如 RETI),从堆栈中恢复 PC 与 PSW,使 CPU 转向新任务的代码执行。(来源:课件第2章 P.57)

5. 请说出会调用 OSSched() 的 5 个系统函数(可以写中文函数名)

在 μC/OS-II 内核中,只要任务状态或优先级发生改变,系统就会调用任务级调度器 OSSched() 尝试触发抢占。会调用该函数的系统函数包括:

  1. 任务创建函数OSTaskCreate() / OSTaskCreateExt()
  2. 延时函数OSTimeDly() / OSTimeDlyHMSM()
  3. 恢复延时函数OSTimeDlyResume()
  4. 挂起自身或其它任务函数OSTaskSuspend()
  5. 恢复被挂起任务函数OSTaskResume()
  6. 发送信号量函数OSSemPost()
  7. 发送消息邮箱函数OSMboxPost()
  8. 发送消息队列函数OSQPost() / OSQPostFront()


二、程序填空题(4个小题 × 5个空 × 1分)

1. 任务创建函数源码

INT8U OSTaskCreate (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio)
{
    OS_STK     *psp;
    INT8U       err;
#if OS_ARG_CHK_EN > 0
    if (prio > OS_LOWEST_PRIO) {             /* [空1] 检测优先级边界 */
        return (OS_PRIO_INVALID);
    }
#endif
    OS_ENTER_CRITICAL();
    if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { 
        OSTCBPrioTbl[prio] = (OS_TCB *)1;    /* [空2] 预留该优先级 */
        OS_EXIT_CRITICAL();
        psp = OSTaskStkInit(task, pdata, ptos, 0); /* [空3] 初始化任务堆栈 */
        err = OSTCBInit(prio, psp, (OS_STK *)0, 0, 0, (void *)0, 0); /* [空4] 初始化任务控制块 */
        if (err == OS_NO_ERR) {
            if (OSRunning == TRUE) {
                OS_Sched();                  /* [空5] 任务级调度 */
            }
        } else {
            OS_ENTER_CRITICAL();
            OSTCBPrioTbl[prio] = (OS_TCB *)0;
            OS_EXIT_CRITICAL();
        }
        return (err);
    }
    OS_EXIT_CRITICAL();
    return (OS_PRIO_EXIST);
}

2. OSSched() 函数源码

void OSSched (void)
{
    INT8U y;
    OS_ENTER_CRITICAL();
    if ((OSLockNesting | OSIntNesting) == 0) {  /* [空1] 确保调度未被锁定且不在中断内 */
        y = OSUnMapTbl[OSRdyGrp];
        OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]); /* [空2] 计算最高优先级 */
        if (OSPrioHighRdy != OSPrioCur) {      /* [空3] 确保最高就绪任务非当前运行任务 */
            OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
            OSCtxSwCtr++;                      /* [空4] 上下文切换计数累加 */
            OS_TASK_SW();                      /* [空5] 执行切换宏 */
        }
    }
    OS_EXIT_CRITICAL();
}

3. OSTimeTick() 源码

void OSTimeTick (void)
{
    OS_TCB *ptcb;
    #if OS_CRITICAL_METHOD == 3
    OS_CPU_SR cpu_sr;
    #endif
    OS_ENTER_CRITICAL();
    OSTime++;                                  /* [空1] 递增系统节拍计数 */
    OS_EXIT_CRITICAL();
    ptcb = OSTCBList;                          /* [空2] 获取活动任务 TCB 链表表头 */
    while (ptcb->OSTCBPrio < OS_LOWEST_PRIO) {
        OS_ENTER_CRITICAL();
        if (ptcb->OSTCBDly != 0) {
            if (--ptcb->OSTCBDly == 0) {
                if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) { /* [空3] 确保任务未被强制挂起 */
                    OSRdyGrp               |= ptcb->OSTCBBitY;
                    OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; /* [空4] 将任务状态改写为就绪 */
                } else {
                    ptcb->OSTCBDly = 1;
                }
            }
        }
        ptcb = ptcb->OSTCBNext;                /* [空5] 指向链表的下一个任务 TCB */
        OS_EXIT_CRITICAL();
    }
}

4. OSSemaphore() 信号量创建源码

OS_EVENT *OSSemCreate (INT16U cnt)
{
    OS_EVENT *pevent;
    #if OS_CRITICAL_METHOD == 3
    OS_CPU_SR cpu_sr;
    #endif
    if (OSIntNesting > 0) {
        return ((OS_EVENT *)0);
    }
    OS_ENTER_CRITICAL();
    pevent = OSEventFreeList;                  /* [空1] 从空闲 ECB 链表中取一个 */
    if (OSEventFreeList != (OS_EVENT *)0) {
        OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; /* [空2] 调整空闲链表头 */
    }
    OS_EXIT_CRITICAL();
    if (pevent != (OS_EVENT *)0) {
        pevent->OSEventType = OS_EVENT_TYPE_SEM; /* [空3] 设置事件类型为信号量 */
        pevent->OSEventCnt  = cnt;             /* [空4] 写入信号量计数初值 */
        pevent->OSEventPtr  = (void *)0;
        OS_EventWaitListInit(pevent);          /* [空5] 初始化等待链表 */
    }
    return (pevent);
}


三、综合题(10 + 20 分)

1. 简述 OSUnMapTbl[] 的赋值原理(10分)

OSUnMapTbl[](优先级判定查找表)是大小为 256 的数组。其核心设计目的是为了通过查表法,在常数时间 O(1)O(1) 内直接检索出 8 位无符号整数中“处于最低有效位(最右侧)的 1 的位数”,从而极速判断出当前系统中就绪的最高任务优先级。(来源:课件第2章 P.45, P.46, P.48)


2. 时间轴分析与输出预测(20分)

/************************Test*************************************/
#include "includes.h"

#define  TASK_STK_SIZE   512                // 任务堆栈长度

OS_STK   StartTaskStk[TASK_STK_SIZE];       // 定义任务堆栈区
OS_STK   MyTaskStk[TASK_STK_SIZE];          // 定义任务堆栈区
OS_STK   YouTaskStk[TASK_STK_SIZE];         // 定义任务堆栈区
OS_STK   HerTaskStk[TASK_STK_SIZE];         // 定义任务堆栈区

INT16S   key;                               // 用于退出的键
char    *s1 = "MyTask正在运行";
char    *s2 = "YouTask正在运行";
char    *s3 = "HerTask正在运行";

INT8U    err;
INT8U    y = 0;                             // 字符显示位置

OS_FLAG_GRP *Sem_F;
OS_FLAGS     Flags;

void  StartTask(void *data);                // 声明起始任务
void  MyTask(void *data);                   // 声明任务
void  YouTask(void *data);                  // 声明任务
void  HerTask(void *data);                  // 声明任务

/************************主函数*********************************/
void main(void)
{
    OSInit();                               // 初始化 uC/OS-II
    PC_DOSSaveReturn();                     // 保存 DOS 环境
    PC_VectSet(uCOS, OSCtxSw);              // 安装 uC/OS-II 中断
    Sem_F = OSFlagCreate(0, &err);          // 创建信号量集

    OSTaskCreate(StartTask,                 // 创建任务 StartTask
                 (void *)0,                 // 给任务传递参数
                 &StartTaskStk[TASK_STK_SIZE - 1], // 设置任务堆栈栈顶
                 0);                        // 使任务的优先级别为 0

    OSStart();                              // 启动多任务管理
}

/***********************任务 StartTask*******************************/
void StartTask(void *pdata)
{
#if OS_CRITICAL_METHOD == 3
    OS_CPU_SR  cpu_sr;
#endif
    pdata = pdata;

    OS_ENTER_CRITICAL();
    PC_VectSet(0x08, OSTickISR);            // 安装时钟中断向量
    PC_SetTickRate(OS_TICKS_PER_SEC);       // 设置 uC/OS-II 时钟频率
    OS_EXIT_CRITICAL();

    OSStatInit();                           // 初始化统计任务

    OSTaskCreate(MyTask,                    // 创建任务 MyTask
                 (void *)0,                 // 给任务传递参数
                 &MyTaskStk[TASK_STK_SIZE - 1], // 设置任务堆栈栈顶
                 3);                        // 使任务的优先级别为 3

    OSTaskCreate(YouTask,                   // 创建任务 YouTask
                 (void *)0,                 // 给任务传递参数
                 &YouTaskStk[TASK_STK_SIZE - 1], // 设置任务堆栈栈顶
                 4);                        // 使任务的优先级别为 4

    OSTaskCreate(HerTask,                   // 创建任务 HerTask
                 (void *)0,                 // 给任务传递参数
                 &HerTaskStk[TASK_STK_SIZE - 1], // 设置任务堆栈栈顶
                 5);                        // 使任务的优先级别为 5

    for (;;)
    {
        // 如果按下 Esc 键则退出 uC/OS-II
        if (PC_GetKey(&key) == TRUE)
        {
            if (key == 0x1B)
            {
                PC_DOSReturn();
            }
        }
        OSTimeDlyHMSM(0, 0, 3, 0);          // 等待 3 秒
    }
}

/************************任务 MyTask*******************************/
void MyTask(void *pdata)
{
#if OS_CRITICAL_METHOD == 3
    OS_CPU_SR  cpu_sr;
#endif
    pdata = pdata;

    for (;;)
    {
        Flags = OSFlagQuery(                // 请求信号量集
            Sem_F,
            //(OS_FLAGS)3,                  // 请求第 0 位和第 1 位信号
            //OS_FLAG_WAIT_SET_ALL, 0,      // 第 0 位和第 1 位信号都为 1 为有效
            &err
        );

        switch (Flags)
        {
        case 1:
            s1 = "第0位信号有效";
            PC_DispStr(10, ++y, s1, DISP_BGND_BLACK + DISP_FGND_WHITE);
            break;
        case 2:
            s1 = "第1位信号有效";
            PC_DispStr(10, ++y, s1, DISP_BGND_BLACK + DISP_FGND_WHITE);
            break;
        case 3:
            s1 = "第0和第1位信号都有效";
            PC_DispStr(10, ++y, s1, DISP_BGND_BLACK + DISP_FGND_WHITE);
            break;
        }

        OSFlagPost(                         // 发送信号量集
            Sem_F,
            (OS_FLAGS)3,                    // 给第 0、1 位发信号
            OS_FLAG_CLR,                    // 信号置 0
            &err
        );

        OSTimeDlyHMSM(0, 0, 2, 0);          // 等待 2 秒
    }
}

/************************任务 YouTask******************************/
void YouTask(void *pdata)
{
#if OS_CRITICAL_METHOD == 3
    OS_CPU_SR  cpu_sr;
#endif
    pdata = pdata;

    for (;;)
    {
        PC_DispStr(10, ++y, s2, DISP_BGND_BLACK + DISP_FGND_WHITE);
        OSTimeDlyHMSM(0, 0, 4, 0);          // 延时 4 秒

        OSFlagPost(                         // 发送信号量集
            Sem_F,
            (OS_FLAGS)2,                    // 给第 1 位发信号
            OS_FLAG_SET,                    // 信号置 1
            &err
        );

        OSTimeDlyHMSM(0, 0, 2, 0);          // 等待 2 秒
    }
}

/************************任务 HerTask******************************/
void HerTask(void *pdata)
{
#if OS_CRITICAL_METHOD == 3
    OS_CPU_SR  cpu_sr;
#endif
    pdata = pdata;

    for (;;)
    {
        PC_DispStr(10, ++y, s3, DISP_BGND_BLACK + DISP_FGND_WHITE);

        if (y < 10)
        {
            OSFlagPost(                     // 发送信号量集
                Sem_F,
                (OS_FLAGS)1,                // 给第 0 位发信号
                OS_FLAG_SET,                // 信号置 1
                &err
            );
        }

        OSTimeDlyHMSM(0, 0, 1, 0);          // 等待 1 秒
    }
}

/************************End**************************************/

(1) 系统任务优先级关系

(2) 任务运行规律分析(以 tt 为系统时间轴,单位:秒/s)


(3) 屏幕前 10 行打印输出预测

根据以上时间轴及变量 yy 的递增过程,屏幕最终输出的前 10 行结果严格为:


在 Github 上编辑此页
分享这篇资料:

下一篇
嵌入式操作系统-2026sp-重点