ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

uC/OS任务创建

2020-01-13 12:58:56  阅读:287  来源: 互联网

标签:R0 创建 任务 STK PendSV OS CPU uC


1.任务的定义

1)定义任务堆栈

1 #define TASK1_STK_SIZE 128 
2 #define TASK2_STK_SIZE 128
3 
4 static CPU_STK Task1Stk[TASK1_STK_SIZE]; 
5 static CPU_STK Task2Stk[TASK2_STK_SIZE];

2)定义任务函数

3)定义任务控制块

任务控制块是一种数据类型,包含着任务的所有信息(任务堆栈,名字,优先级,链表指针等),任务的执行是通过系统的调度,系统对任务的操作则是通过任务控制块来实现

4)定义任务函数

2.系统初始化

系统初始化一般是在硬件初始化完成之后进行

3.启动系统

1 void OSStart (OS_ERR *p_err)
2 {
3     if ( OSRunning == OS_STATE_OS_STOPPED ) { 
4     /* 手动配置任务 1 先运行 */
5     OSTCBHighRdyPtr = OSRdyList[0].HeadPtr; 
6 
7     /* 启动任务切换*/
8     OSStartHighRdy(); 
9 
10     /* 不会运行到这里,运行到这里表示发生了致命的错误 */
11     *p_err = OS_ERR_FATAL_RETURN;
12     } else {
13     *p_err = OS_STATE_OS_RUNNING;
14     }
15 }
/***********************  OSStartHighRdy()  ***************************/
OSStartHighRdy
LDR R0, = NVIC_SYSPRI14 ; 设置 PendSV 异常优先级为最低(在 uC/OS-III 中,上下文切换是在 PendSV 异常服务程序中执行的,配置 PendSV的优先级为最低,防止在中断服务程序中执行上下文切换)
LDR R1, = NVIC_PENDSV_PRI
STRB R1, [R0]

MOVS R0, #0 ;设置 psp 的值为 0,开始第一次上下文切换
MSR PSP, R0

LDR R0, =NVIC_INT_CTRL ; 触发 PendSV 异常
LDR R1, =NVIC_PENDSVSET
STR R1, [R0]
18
19 CPSIE I ; 使能总中断,NMI 和 HardFault 除外
20
21 OSStartHang
22 B OSStartHang ; 程序应永远不会运行到这里
/************************************************************************/

4.任务切换

当调用 OSStartHighRdy()函数时会触发 PendSV 异常,然后在PendSV 异常服务函数里面进行任务切换。
PendSV 异常服务函数名称必须与启动文件里面向量表中 PendSV 的向量名一致,如果不一致则内核是响应
不了用户编写的 PendSV 异常服务函数的,只响应启动文件里面默认的 PendSV 异常服务函数。启动文件里
面为每个异常都编写好默认的异常服务函数,函数体都是一个死循环,当发现代码跳转到这些启动文件里面默
认的异常服务函数的时候,就要检查下异常函数名称是否写错了,是否跟向量表里面的一致。

/************************   PendSV_Handler()  ****************************/
PendSV_Handler
PendSV_Handler
; 关中断,NMI 和 HardFault 除外,防止上下文切换被中断
CPSID I (1)

; 将 psp 的值加载到 R0
MRS R0, PSP (2)

; 判断 R0,如果值为 0 则跳转到 OS_CPU_PendSVHandler_nosave
; 进行第一次任务切换的时候,R0 肯定为 0
CBZ R0, OS_CPU_PendSVHandler_nosave (3)

;-----------------------一、保存上文-----------------------------
; 任务的切换,即把下一个要运行的任务的堆栈内容加载到 CPU 寄存器中
;-------------------------------------------------------------- 
; 在进入 PendSV 异常的时候,当前 CPU 的 xPSR,PC(任务入口地址),
; R14,R12,R3,R2,R1,R0 会自动存储到当前任务堆栈,
; 同时递减 PSP 的值,随便通过 代码:MRS R0, PSP 把 PSP 的值传给 R0

; 手动存储 CPU 寄存器 R4-R11 的值到当前任务的堆栈
STMDB R0!, {R4-R11} 

; 加载 OSTCBCurPtr 指针的地址到 R1,这里 LDR 属于伪指令
LDR R1, = OSTCBCurPtr (16)
; 加载 OSTCBCurPtr 指针到 R1,这里 LDR 属于 ARM 指令
LDR R1, [R1] (17)
;  存储 R0 的值到 OSTCBCurPtr->OSTCBStkPtr,这个时候 R0 存的是任务空闲栈的栈顶
STR R0, [R1] (18)

;-----------------------二、切换下文-----------------------------
; 实现 OSTCBCurPtr = OSTCBHighRdyPtr
; 把下一个要运行的任务的堆栈内容加载到 CPU 寄存器中
;--------------------------------------------------------------
OS_CPU_PendSVHandler_nosave (4)

; 加载 OSTCBCurPtr 指针的地址到 R0,这里 LDR 属于伪指令
LDR R0, = OSTCBCurPtr (5)
; 加载 OSTCBHighRdyPtr 指针的地址到 R1,这里 LDR 属于伪指令
LDR R1, = OSTCBHighRdyPtr (6)
; 加载 OSTCBHighRdyPtr 指针到 R2,这里 LDR 属于 ARM 指令 
LDR R2, [R1] (7)
; 存储 OSTCBHighRdyPtr 到 OSTCBCurPtr
STR R2, [R0] (8)

; 加载 OSTCBHighRdyPtr 到 R0 
LDR R0, [R2] (9)
; 加载需要手动保存的信息到 CPU 寄存器 R4-R11
LDMIA R0!, {R4-R11} (10)

; 更新 PSP 的值,这个时候 PSP 指向下一个要执行的任务的堆栈的栈底
;(这个栈底已经加上刚刚手动加载到 CPU 寄存器 R4-R11 的偏移) 
MSR PSP, R0 (11)

; 确保异常返回使用的堆栈指针是 PSP,即 LR 寄存器的位 2 要为 1
ORR LR, LR, #0x04 (12) 

; 开中断
CPSIE I (13)

; 异常返回,这个时候任务堆栈中的剩下内容将会自动加载到 xPSR,
; PC(任务入口地址),R14,R12,R3,R2,R1,R0(任务的形参)
; 同时 PSP 的值也将更新,即指向任务堆栈的栈顶。
; 在 STM32 中,堆栈是由高地址向低地址生长的。
BX LR 
/*************************************************************************/

5.程序示例

/*
*******************************************************************
* 包含的头文件
*******************************************************************
*/
#include "os.h"
#include "stm32f4xx_hal.h"

/*
*******************************************************************
* 宏定义
*******************************************************************
*/


/*
*******************************************************************
* 全局变量
*******************************************************************
*/



/*
*******************************************************************
* TCB & STACK & 任务声明
*******************************************************************
*/
#define TASK1_STK_SIZE 20
#define TASK2_STK_SIZE 20

static CPU_STK Task1Stk[TASK1_STK_SIZE];
static CPU_STK Task2Stk[TASK2_STK_SIZE];

static OS_TCB Task1TCB;
static OS_TCB Task2TCB;

void Task1( void *p_arg );
void Task2( void *p_arg );

/*
*******************************************************************
* 函数声明
*******************************************************************
*/


/*
*******************************************************************
* main 函数
*******************************************************************
*/
/*
* 注意事项:1、该工程使用软件仿真,debug 需选择 Ude Simulator
* 2、在 Target 选项卡里面把晶振 Xtal(Mhz)的值改为 25,默认是 12,
* 改成 25 是为了跟 system_ARMCM3.c 中定义的__SYSTEM_CLOCK 相同,
* 确保仿真的时候时钟一致
*/
int main(void)
{
    OS_ERR err;

    /* 初始化相关的全局变量 */
    OSInit(&err);

    /* 创建任务 */
    OSTaskCreate ((OS_TCB*) &Task1TCB,
        (OS_TASK_PTR ) Task1,
        (void *) 0,
        (CPU_STK*) &Task1Stk[0],
        (CPU_STK_SIZE) TASK1_STK_SIZE,
        (OS_ERR *) &err);

        OSTaskCreate ((OS_TCB*) &Task2TCB,
        (OS_TASK_PTR ) Task2,
        (void *) 0,
        (CPU_STK*) &Task2Stk[0],
        (CPU_STK_SIZE) TASK2_STK_SIZE,
        (OS_ERR *) &err);

        /* 将任务加入到就绪列表 */
        OSRdyList[0].HeadPtr = &Task1TCB;
        OSRdyList[1].HeadPtr = &Task2TCB;

        /* 启动 OS,将不再返回 */
        OSStart(&err);
}
/*
*******************************************************************
* 函数实现
*******************************************************************
*/

/* 任务 1 */
void Task1( void *p_arg )
{
    while(1)
    {
    /*******  功能实现  *********/
    .....
    /***************************/
    
    /* 手动切换任务 */
        OSSched();
    }

}

/* 任务 2 */
void Task2( void *p_arg )
{
    while(1)
    {
    /*******  功能实现  *********/
    .....
    /***************************/
    
    /* 手动切换任务 */
        OSSched();
    }

}

/*************  OSSched()  *****************/
/* 任务切换,实际就是触发 PendSV 异常,然后在 PendSV 异常中进行上下文切换 */
void OSSched (void)
{
    if ( OSTCBCurPtr == OSRdyList[0].HeadPtr ) {
        OSTCBHighRdyPtr = OSRdyList[1].HeadPtr;
        } else {
        OSTCBHighRdyPtr = OSRdyList[0].HeadPtr;
    }

    OS_TASK_SW();   //触发 PendSV异常
}
/*******************************************/

标签:R0,创建,任务,STK,PendSV,OS,CPU,uC
来源: https://www.cnblogs.com/taury/p/12186695.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有