阻塞延时与空闲任务

2024/1/12 stm32

去掉延时函数,使用空闲任务。避免阻塞运行

# 实现空闲任务

# 1.定义空闲任务堆栈

#ifndef OS_CFG_APP_H
#define OS_CFG_APP_H

/* 空闲任务堆栈大小 */
#define  OS_CFG_IDLE_TASK_STK_SIZE       128u

#endif  /* OS_CFG_APP_H */

os_cfg_app.c 文件代码

#include <os_cfg_app.h>
#include <os.h>

CPU_STK        OSCfg_IdleTaskStk   [OS_CFG_IDLE_TASK_STK_SIZE];

/* 空闲任务堆栈起始地址 */
CPU_STK      * const  OSCfg_IdleTaskStkBasePtr   = (CPU_STK    *)&OSCfg_IdleTaskStk[0];
/* 空闲任务堆栈大小 */
CPU_STK_SIZE   const  OSCfg_IdleTaskStkSize      = (CPU_STK_SIZE)OS_CFG_IDLE_TASK_STK_SIZE;

空闲任务的堆栈的起始地址和大小均被定义成一个常量,不能被 修改。

os.h中声明

/* 空闲任务堆栈起始地址 */
extern CPU_STK      * const  OSCfg_IdleTaskStkBasePtr;
/* 空闲任务堆栈大小 */
extern CPU_STK_SIZE   const  OSCfg_IdleTaskStkSize;

# 2.定义空闲任务 TCB

os.h中定义

/* 空闲任务 TCB */
OS_EXT    OS_TCB         OSIdleTaskTCB;

# 3.定义空闲任务函数

// os_type.h
typedef   CPU_INT32U      OS_IDLE_CTR;
// os.h
/* 空闲任务计数变量 */
OS_EXT    OS_IDLE_CTR    OSIdleTaskCtr;

os_core.c

/* 空闲任务 */
void  OS_IdleTask (void  *p_arg)
{
	p_arg = p_arg;
	
	/* 空闲任务什么都不做,只对全局变量OSIdleTaskCtr ++ 操作 */
	for(;;)
	{
		OSIdleTaskCtr++;
	}
}

# 4.空闲任务初始化

空闲任务初始化 os_core.c

/* 空闲任务初始化 */
void  OS_IdleTaskInit(OS_ERR  *p_err)
{	
	/* 初始化空闲任务计数器 */
	OSIdleTaskCtr = (OS_IDLE_CTR)0;
	
	/* 创建空闲任务 */
	OSTaskCreate( (OS_TCB     *)&OSIdleTaskTCB, 
			      (OS_TASK_PTR )OS_IdleTask, 
			      (void       *)0,
			      (CPU_STK    *)OSCfg_IdleTaskStkBasePtr,
			      (CPU_STK_SIZE)OSCfg_IdleTaskStkSize,
			      (OS_ERR     *)p_err );
}

调用代码

os_core.c

/* RTOS初始化
** 初始化全局变量
*/
void OSInit (OS_ERR *p_err)
{
	/* 配置OS初始状态为停止态 */
	OSRunning =  OS_STATE_OS_STOPPED;
	
	/* 初始化两个全局TCB,这两个TCB用于任务切换 */
	OSTCBCurPtr = (OS_TCB *)0;
	OSTCBHighRdyPtr = (OS_TCB *)0;
	
	/* 初始化就绪列表 */
	OS_RdyListInit();
	
	/* 初始化空闲任务 */
	OS_IdleTaskInit(p_err);
	
	if (*p_err != OS_ERR_NONE) 
	{
        return;
    }
}

# 实现阻塞延时

os_time.c

/* 阻塞延时 */
void  OSTimeDly(OS_TICK dly)
{
	/* 设置延时时间 */
	OSTCBCurPtr->TaskDelayTicks = dly;
	
	/* 进行任务调度 */
	OSSched();	
}

os_tcp增加任务延时周期个数

struct os_tcb
{
	CPU_STK         *StkPtr;
	CPU_STK_SIZE    StkSize;
	
	/* 任务延时周期个数 */
	OS_TICK         TaskDelayTicks;
};

任务调度os_core.c

/* 任务切换,实际就是触发PendSV异常,然后在PendSV异常中进行上下文切换 */
void OSSched(void)
{
	
    /* 如果当前任务是空闲任务,那么就去尝试执行任务1或者任务2,看看他们的延时时间是否结束
       如果任务的延时时间均没有到期,那就返回继续执行空闲任务 */
    if( OSTCBCurPtr == &OSIdleTaskTCB )
    {
        if(OSRdyList[0].HeadPtr->TaskDelayTicks == 0)
        {
            OSTCBHighRdyPtr = OSRdyList[0].HeadPtr;
        }
        else if(OSRdyList[1].HeadPtr->TaskDelayTicks == 0)
        {
            OSTCBHighRdyPtr = OSRdyList[1].HeadPtr;
        }
        else
        {
            return;		/* 任务延时均没有到期则返回,继续执行空闲任务 */
        } 
    }
    else
    {
        /*如果是task1或者task2的话,检查下另外一个任务,如果另外的任务不在延时中,就切换到该任务
        否则,判断下当前任务是否应该进入延时状态,如果是的话,就切换到空闲任务。否则就不进行任何切换 */
        if(OSTCBCurPtr == OSRdyList[0].HeadPtr)
        {
            if(OSRdyList[1].HeadPtr->TaskDelayTicks == 0)
            {
                OSTCBHighRdyPtr = OSRdyList[1].HeadPtr;
            }
            else if(OSTCBCurPtr->TaskDelayTicks != 0)
            {
                OSTCBHighRdyPtr = &OSIdleTaskTCB;
            }
            else 
            {
                return;		/* 返回,不进行切换,因为两个任务都处于延时中 */
            }
        }
        else if(OSTCBCurPtr == OSRdyList[1].HeadPtr)
        {
            if(OSRdyList[0].HeadPtr->TaskDelayTicks == 0)
            {
                OSTCBHighRdyPtr = OSRdyList[0].HeadPtr;
            }
            else if(OSTCBCurPtr->TaskDelayTicks != 0)
            {
                OSTCBHighRdyPtr = &OSIdleTaskTCB;
            }
            else 
            {
                return;		/* 返回,不进行切换,因为两个任务都处于延时中 */
            }
        }
    }
	
	/* 任务切换 */
    // 触发PendSV异常
	OS_TASK_SW();
}

# main 函数

设置延时

OSTimeDly(2);

完整代码

#include "os.h"
#include "ARMCM3.h"


uint32_t flag1;
uint32_t flag2;

#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 );

/*
************************************************************************************************************************
*                                                  函数声明
************************************************************************************************************************
*/
void delay(uint32_t count);

/*******************************************************************************************************
*                                                    main函数
*******************************************************************************************************/
/*
* 注意事项:1、该工程使用软件仿真,debug需选择 Ude Simulator
*           2、在Target选项卡里面把晶振Xtal(Mhz)的值改为25,默认是12,
*              改成25是为了跟system_ARMCM3.c中定义的__SYSTEM_CLOCK相同,确保仿真的时候时钟一致
*/
int main(void)
{	
	OS_ERR err;
	
	/* 关闭中断 */
	CPU_IntDis();
	
	/* 配置SysTick 10ms 中断一次 */
	OS_CPU_SysTickInit (10);
	
	/* 初始化相关的全局变量 */
	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 )
{
	for( ;; )
	{
		flag1 = 1;
		//delay( 100 );
		OSTimeDly(2);		
		flag1 = 0;
		//delay( 100 );
		OSTimeDly(2);
		
		/* 任务切换,这里是手动切换 */		
		//OSSched();
	}
}

/* 任务2 */
void Task2( void *p_arg )
{
	for( ;; )
	{
		flag2 = 1;
		//delay( 100 );
		OSTimeDly(2);		
		flag2 = 0;
		//delay( 100 );
		OSTimeDly(2);
		
		/* 任务切换,这里是手动切换 */
		//OSSched();
	}
}