UCOSIII_多任务创建(二)

任务调度和切换就是让就绪表中优先级最高的任务获得CPU使用权,UCOSIII是抢占式的,高优先级任务可以抢了低优先级任务的CPU使用权,任务调度由任务调度器完成,任务调度器分为:任务级,中断级调度器

1.任务级调度器:OSSched(),不能用于中断服务函数中
函数里有一个函数OS_TASK_SW(),这个是真正执行任务切换的宏,它把当前任务的CPU寄存器值保存在任务堆栈中,保存完当前任务的现场后将新任务的OS_TCB中保存的任务堆栈指针的值加载到CPU的堆栈指针寄存器中,新任务结束后还要把CPU寄存器值变回旧任务的。

2.中断级调度器:OSIntEnter(),OSIntExit(),调用此函数时中断应该是关闭的
函数里有一个函数OSIntCtxSW(),这个是真正执行任务切换的宏,进入中断时硬件自动保存现场了,将新任务的OS_TCB中保存的任务堆栈指针的值加载到CPU的堆栈指针寄存器中,新中断结束后自动恢复现场。

3.时间片轮转调度:UCOSIII支持一个优先级下有多个任务,不过允许一个任务运行一段时间(时间片)后让出CPU使用权,让同优先级下的洗一个任务运行,这种任务调度方法就是时间片轮转调度。如果同级下第一个任务设置的时间片用完则第一个任务排到链表尾,等待下一次调度。使用OSSchedRoundRobinYield()可以放弃剩余的时间片,在同级下其它任务运行。

通常创建多个任务,可以先在main函数中设置一个任务,然后在这个任务里创建多个任务.
每个任务都有自己的任务函数。

#include "system.h"
#include "led.h"
#include "includes.h"

//任务优先级
#define START_TASK_PRIO     3
//任务堆栈大小    
#define START_STK_SIZE      512
//任务控制块
OS_TCB StartTaskTCB;
//任务堆栈  
CPU_STK START_TASK_STK[START_STK_SIZE];
//任务函数
void start_task(void *p_arg);

#define LED1_TASK_PRIO      4   
#define LED1_STK_SIZE       128
OS_TCB Led1TaskTCB; 
CPU_STK LED1_TASK_STK[LED1_STK_SIZE];
void led1_task(void *p_arg);

#define LED2_TASK_PRIO      5   
#define LED2_STK_SIZE       128
OS_TCB Led2TaskTCB; 
CPU_STK LED2_TASK_STK[LED2_STK_SIZE];
void led2_task(void *p_arg);

int main()
{   
    OS_ERR err;
    LED_Init();
    OSInit(&err);       //初始化UCOSIII
    //创建开始任务
    OSTaskCreate((OS_TCB    * )&StartTaskTCB,       //任务控制块
                 (CPU_CHAR  * )"start task",        //任务名字
                 (OS_TASK_PTR )start_task,          //任务函数
                 (void      * )0,                   //传递给任务函数的参数
                 (OS_PRIO     )START_TASK_PRIO,     //任务优先级
                 (CPU_STK   * )&START_TASK_STK[0],  //任务堆栈基地址
                 (CPU_STK_SIZE)START_STK_SIZE/10,   //任务堆栈深度限位
                 (CPU_STK_SIZE)START_STK_SIZE,      //任务堆栈大小
                 (OS_MSG_QTY  )0,                   //任务内部消息队列能够接收的最大消息数目,为0时禁止接收消息
                 (OS_TICK     )0,                   //当使能时间片轮转时的时间片长度,为0时为默认长度,
                 (void      * )0,                   //用户补充的存储区
                 (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, //任务选项
                 (OS_ERR    * )&err);               //存放该函数错误时的返回值 
    OSStart(&err);  //开启UCOSIII
}

//开始任务函数
void start_task(void *p_arg)
{
    OS_ERR err;
    
    CPU_INT32U  cpu_clk_freq;
    CPU_INT32U  cnts;
    
    CPU_SR_ALLOC();
    p_arg = p_arg; //防止报错

    CPU_Init();
    
    cpu_clk_freq = BSP_CPU_ClkFreq();                           /* Determine SysTick reference freq.                    */
    cnts = cpu_clk_freq / (CPU_INT32U)OSCfg_TickRate_Hz;        /* Determine nbr SysTick increments                     */
    OS_CPU_SysTickInit(cnts);                                   /* Init uC/OS periodic time src (SysTick).              */

    Mem_Init();       
    
    
#if OS_CFG_STAT_TASK_EN > 0u
   OSStatTaskCPUUsageInit(&err);    //统计任务                
#endif
    
#ifdef CPU_CFG_INT_DIS_MEAS_EN      //如果使能了测量中断关闭时间
    CPU_IntDisMeasMaxCurReset();    
#endif
    
#if OS_CFG_SCHED_ROUND_ROBIN_EN  //当使用时间片轮转的时候
     //使能时间片轮转调度功能,时间片长度为1个系统时钟节拍,既1*5=5ms
    OSSchedRoundRobinCfg(DEF_ENABLED,1,&err);  
#endif      
    
    OS_CRITICAL_ENTER();    //进入临界区
    //创建LED1任务
    OSTaskCreate((OS_TCB    * )&Led1TaskTCB,        
                 (CPU_CHAR  * )"led1 task",         
                 (OS_TASK_PTR )led1_task,           
                 (void      * )0,                   
                 (OS_PRIO     )LED1_TASK_PRIO,     
                 (CPU_STK   * )&LED1_TASK_STK[0],   
                 (CPU_STK_SIZE)LED1_STK_SIZE/10,    
                 (CPU_STK_SIZE)LED1_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);

    //创建LED2任务
    OSTaskCreate((OS_TCB    * )&Led2TaskTCB,        
                 (CPU_CHAR  * )"led2 task",         
                 (OS_TASK_PTR )led2_task,           
                 (void      * )0,                   
                 (OS_PRIO     )LED2_TASK_PRIO,     
                 (CPU_STK   * )&LED2_TASK_STK[0],   
                 (CPU_STK_SIZE)LED2_STK_SIZE/10,    
                 (CPU_STK_SIZE)LED2_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);
                 
    OS_TaskSuspend((OS_TCB*)&StartTaskTCB,&err);        //挂起开始任务             
    OS_CRITICAL_EXIT(); //进入临界区
}

//led1任务函数
void led1_task(void *p_arg)
{
    OS_ERR err;
    p_arg = p_arg;
    while(1)
    {
        led1=!led1;
        OSTimeDlyHMSM(0,0,0,200,OS_OPT_TIME_HMSM_STRICT,&err); //延时200ms
    }
}

//led2任务函数
void led2_task(void *p_arg)
{
    OS_ERR err;
    p_arg = p_arg;
    while(1)
    {
        led2=!led2;
        OSTimeDlyHMSM(0,0,0,400,OS_OPT_TIME_HMSM_STRICT,&err); //延时400ms
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值