阻塞延时与空闲任务
土豆 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();
}
}