当前位置: 首页 > news >正文

uCOS3实时操作系统(系统初始化和任务启动)

文章目录

  • ucos初始化
  • 任务创建
  • 任务启动

ucos初始化

  • 系统运行的过程如下:OSInit -> OSTaskCreate -> OSStart
  • ucos初始化主要在 OSInit 中进行,下面列举了该初始化过程中比较重要的几个步骤:
    OSInit()OSInitHook();OS_CPU_ExceptStkBase //将异常栈的栈底(OS_CPU_ExceptStkBase)按 8 字节对齐OS_KA_BASEPRI_Boundary	//初始化全局变量 OS_KA_BASEPRI_Boundary 的值,该全局变量用于设置 BASEPRI 寄存器OSIntNestingCtr = 0u;//中断嵌套计数OSRunning = OS_STATE_OS_STOPPED; //内核运行状态OSSchedLockNestingCtr = 0u;//任务调度器锁定嵌套计数OSTCBCurPtr = (OS_TCB *)0;/* 指向当前任务的任务控制块的指针 */OSTCBHighRdyPtr = (OS_TCB *)0;/* 指向优先级最高的任务的任务控制块的指针 */OSPrioCur = 0u;/* 当前任务的任务优先级 */OSPrioHighRdy = 0u;/* 优先级最高的任务的任务优先级 */p_stk = OSCfg_ISRStkBasePtr;  // 任务异常栈空间清零处理,该栈空间是一个全局变量…… //一些其他的必要的初始化(但是对于程序分析不是很重要没写入进来)OS_PrioInit();for (i = 0u; i < OS_PRIO_TBL_SIZE; i++) {  //OS_PRIO_TBL_SIZE此变量通过设置的最大优先级数量动态调整OSPrioTbl[i] = 0u;			//我们设置32,刚好一个数组只需要一个字即可装下32bit,此处是进行清零操作}							//若后续创建了新的任务则对应的bit会置1,bit31对应优先级0OS_RdyListInit();p_rdy_list = &OSRdyList[i];   //这 OS_CFG_PRIO_MAX 个就绪态任务链表被存放在数组 OSRdyList[OS_CFG_PRIO_MAX中p_rdy_list->HeadPtr    = (OS_TCB *)0;  //数组 OSRdyList 的一个元素就代表一个就绪态任务链表p_rdy_list->TailPtr    = (OS_TCB *)0;OS_TaskInit(p_err);  // 任务管理的初始化,将任务数量计数器清零,将任务切换次数计数器清零OS_IdleTaskInit(p_err);  //创建空闲任务及其相关初始化变量OS_TickInit(p_err);OSTickCtr             = 0u;//将系统时钟节拍计数器(OSTickCtr)清零OSTickList.NbrEntries = 0u;  //将 Tick 任务链表(OSTickList)中指向下一个 Tick 任务控制块的指针清空OSTickList.NbrUpdated = 0u;OS_StatTaskInit(p_err);  //创建统计任务及其相关初始化变量OS_TmrInit(p_err);  //创建软件定时器任务及其相关初始化变量OSCfg_Init();  //主要用于保证一些未使用到的变量不会被编译器优化掉,中途可能会用到OSInitialized = OS_TRUE; //µC/OS-III 内核初始化状态
    

任务创建

  • 下面是一个简单的任务创建函数
    OSTaskCreate(   (OS_TCB        *)&StartTask_TCB,(CPU_CHAR      *)"start_task",(OS_TASK_PTR    )start_task,(void          *)0,(OS_PRIO        )START_TASK_PRIO,(CPU_STK       *)StartTask_STK,(CPU_STK_SIZE   )START_STK_SIZE / 10,(CPU_STK_SIZE   )START_STK_SIZE,(OS_MSG_QTY     )0,(OS_TICK        )0,(void          *)0,(OS_OPT         )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),(OS_ERR        *)&err);
    
  • 接下面简要说明一下创建具体过程
    OSTaskCreate……	//各种可能的错误检查,如栈空间大小检测,中断中非法调用等等OS_TaskInitTCB(p_tcb);  //初始化任务控制块中成员变量的值为0#if (CPU_CFG_STK_GROWTH == CPU_STK_GROWTH_HI_TO_LO)  //栈的生长方向是与硬件有关的p_stk_limit = p_stk_base + stk_limit;  //根据栈的生长方向确定 “水位”限制的大小,因为传入是一个值不是地址#elsep_stk_limit = p_stk_base + (stk_size - 1u) - stk_limit;#endifp_sp = OSTaskStkInit(p_task, //初始化任务栈,详细内容参考后面注释1p_arg,p_stk_base,p_stk_limit,stk_size,opt);p_tcb->StkPtr        = p_sp; //将更新后的栈指针更新至任务控制块的栈指针中…… //根据函数传入的参数初始化任务控制块中的成员变量CPU_CRITICAL_ENTER();  //进入临界区OS_PrioInsert(p_tcb->Prio);   //更新在init函数中创建的优先级位图表OS_RdyListInsertTail(p_tcb);  //任务插入就绪态任务链表,将对应的链表的前后指针都设置为任务控制块地址OSTaskQty++;   //任务数量+1CPU_CRITICAL_EXIT();  //退出临界区OSSched();  //任务切换,这个是下一章节的内容,此时OSRunning还是stoppped状态,会直接退出该函数,需要经过OSStart()函数改变此状态才行。
    
  • 注释1 初始化任务栈,任务创建时会在栈的最开始位置创建一个如下图所示的任务栈空间方便后期进行切换,且任务栈创建成功后会将更新后的栈指针更新至任务控制块的栈指针中,便于后期进行出栈操
    在这里插入图片描述
    在这里插入图片描述
    对应的函数实现如下图所示:
    在这里插入图片描述

任务启动

  • 开始 µC/OS-III 任务调度是 µC/OS-III 内核开始运行前的最后一步,在此之前需要先调用函数 OSInit()对 µC/OS-III 内核进行初始化,并至少创建一个应用任务。通过调用函数 OSStart()就能够开始 µC/OS-III 的任务调度。

    OSStart(&err);if (OSInitialized != OS_TRUE) {  //判断用户在此之前是否没有初始化操作系统*p_err = OS_ERR_OS_NOT_INIT;return;}if (OSTaskQty <= kernel_task_cnt) { //判断用户在此之前是否没有创建应用任务*p_err = OS_ERR_OS_NO_APP_TASK;return;}if (OSRunning == OS_STATE_OS_STOPPED) {OSPrioHighRdy   = OS_PrioGetHighest();  //就绪态任务的任务优先级以位图的当时记录在数组 OSPrioTbl 中通过计算前导零的方式就能够非常方便地获取就绪态任务中最高的任务优先级OSPrioCur       = OSPrioHighRdy;OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;OSTCBCurPtr     = OSTCBHighRdyPtr;  //获取最高优先级任务控制块的指针OSRunning       = OS_STATE_OS_RUNNING;  //将状态改为启动OSStartHighRdy();  //此函数是任务开始调度的核心,下面会进一步讲解*p_err           = OS_ERR_FATAL_RETURN;}
    
  • 函数 OSStartHighRdy()是在文件 os_cpu_a.asm 中定义的一个标号,注意此处与任务创建函数中的任务栈初始化联系十分紧密,将初始化任务栈中的寄存器全部都出栈到CPU寄存器里面,代码如下:

    OSStartHighRdyCPSID   I                                                   ; Prevent interruption during context switchMOV32   R0, NVIC_SYSPRI14                                   ; Set the PendSV exception priorityMOV32   R1, NVIC_PENDSV_PRISTRB    R1, [R0]MOVS    R0, #0                                              ; Set the PSP to 0 for initial context switch callMSR     PSP, R0MOV32   R0, OS_CPU_ExceptStkBase                            ; Initialize the MSP to the OS_CPU_ExceptStkBaseLDR     R1, [R0]MSR     MSP, R1BL      OSTaskSwHook                                        ; Call OSTaskSwHook() for FPU Push & PopMOV32   R0, OSPrioCur                                       ; OSPrioCur   = OSPrioHighRdy;MOV32   R1, OSPrioHighRdyLDRB    R2, [R1]STRB    R2, [R0]MOV32   R0, OSTCBCurPtr                                     ; OSTCBCurPtr = OSTCBHighRdyPtr;MOV32   R1, OSTCBHighRdyPtrLDR     R2, [R1]STR     R2, [R0]LDR     R0, [R2]                                            ; R0 is new process SP; SP = OSTCBHighRdyPtr->StkPtr;MSR     PSP, R0                                             ; Load PSP with new process SPMRS     R0, CONTROLORR     R0, R0, #2BIC     R0, R0, #4                                          ; Clear FPCA bit to indicate FPU is not in useMSR     CONTROL, R0ISB                                                         ; Sync instruction streamLDMFD    SP!, {R4-R11, LR}                                  ; Restore r4-11, lr from new process stackLDMFD    SP!, {R0-R3}                                       ; Restore r0, r3LDMFD    SP!, {R12, LR}                                     ; Load R12 and LRLDMFD    SP!, {R1, R2}                                      ; Load PC and discard xPSRCPSIE    IBX       R1
    
  • 需要注意的是,在我们使用裸机进行中断任务切换的时候不管主程序还是中断都是使用的是MSP堆栈指针,而在ucos操作系统中我们在主程序的任务切换上使用的是PSP堆栈指针,在中断系统调度上中我们使用的是MSP堆栈指针,此外,在中断进行时,系统会自动出入栈除R4-R11以外的寄存器。
    在这里插入图片描述
    在这里插入图片描述

  • 控制寄存器选择当前使用哪个堆栈指针。
    在这里插入图片描述

  • 在上面的代码中用到了入栈出栈相关的指令,具体的描述如下图所示:
    在这里插入图片描述

相关文章:

  • 《Learning Langchain》阅读笔记5-RAG(1)
  • 7. 服务通信 ---- 使用自定义srv,服务方和客户方cpp,python文件编写
  • MATLAB 训练CNN模型 yolo v4
  • 强化学习框架verl源码学习-快速上手之如何跑通PPO算法
  • Linux学习笔记协议篇(六):SPI FLASH设备驱动
  • 嵌入式人工智能应用-第三章 opencv操作8 图像特征之HOG 特征
  • 网络原理 - 3(UDP 协议)
  • 读文献先读图:韦恩图怎么看?
  • 设备、管道绝热(保冷)设计计算
  • Flutter路由模块化管理方案
  • 文件包含漏洞,目录遍历漏洞,CSRF,SSRF
  • 深度解析云计算:概念、优势与分类全览
  • 爬虫获取sku信息需要哪些库
  • 用银河麒麟 LiveCD 快速查看原系统 IP 和打印机配置
  • 网页下载的m3u8格式文件使用FFmpeg转为MP4
  • three.js中的instancedMesh类优化渲染多个同网格材质的模型
  • 你的大模型服务如何压测:首 Token 延迟、并发与 QPS
  • JavaScript — 总结
  • 基于XC7V690T的在轨抗单粒子翻转系统设计
  • 【数学建模】随机森林算法详解:原理、优缺点及应用
  • 全国总工会成立100周年,工运历史和发展成就展将对外展出
  • 新片|真人版《星际宝贝史迪奇》5月23日与北美同步上映
  • 湖南平江发生一起意外翻船事件,6人不幸溺亡
  • 北美票房|《罪人》成首部观众评分为A级的恐怖片
  • 豫章故郡,剑指演艺经济新高地
  • 寻女19年的“棉花糖爸爸”明将办团圆宴,大女儿:妹妹是片区销售主管