时间片轮询多任务操作系统( TinyOS51 V1.2 )

时间:2021-04-25 19:23:43

选自<<项目驱动-单片机应用设计基础>>

 

//注意了:在初始化信号量时一定要为其赋初值,并将获得信号量事件列表清空


//
事件的返回值( tiny_os_51.h ) #define TN_OS_OK 0 //正确 #define TN_OS_PAR_ERR -1 //参数错误 #define TN_OS_TIME_OUT -2 //等待时间到 #define TN_OS_EVENT_FULL -3 //事件已满 //由于任务在同一时刻只能等待一个事件,因此,可以用指向等待事件的指针pvEvent指示任务正在等待哪个具体的事件 //注意了 __GtcbTasks[ __GthTaskCur ].pvEvent = ( data void * )0; //无等待的事件 //任务控制块( tiny_os_51_core.c ) #define __TN_TASK_FLG_DEL 0x00 //任务被删除 #define __TN_TASK_FLG_RDY 0x01 //任务就绪 #define __TN_TASK_FLG_DLY 0x02 //任务延时 #define __TN_TASK_FLG_SEM 0x04 //任务等待信号量 struct tn_os_tcb { jmp_buf jbTaskContext; //用于存储上下文信息 unsigned char ucTaskStat; //任务状态子 unsigned int uiTicks; //任务延时 data void *pvEvent; //指向等待事件的指针 }; typedef struct tn_os_tcb TN_OS_TCB; //TN_OS_TCB等效于struct tn_os_tcb static data TN_OS_TCB __GtcbTasks[ TN_OS_MAS_TASKS ]; //任务控制块的结构体数组 //关于一般操作系统 //操作系统的信号量中都包含等待任务列表,如下 struct xxxx_sem { //信号量计数值 //其他辅助成员 //等待任务列表 } typedef struct tn_os_sem XXXX_SEM; //针对不同的操作系统,"信号量计数值"可能8位,16位,或者32位整数,而"等任务列表"可能是 //一个成员,也可能是由多个成员( 可以认为是一个结构体,只是没有明确定义出来罢了 ) //OS初始化( tiny_os_51_core.c ) void tnOsInit ( void ) { TN_OS_TASK_HANDLE tnTask; //操作的任务 for ( tnTask = 0; tnTask < TN_OS_MAX_TASKS; tnTask ++ ) { __GtcbTasks[ tnTask ].ucTaskStat = __TN_TASK_FLG_DEL; //使任务处于删除状态 __GtcbTasks[ thTask ].uiTasks = 0; //无限延时 __GtcbTasks[ thTask ].pvEvent = ( data void * )0; //无等待的事件 } __GthTaskCur = 0; //初始化任务号为0 } //信号的定义( tiny_os_51.h ) //这里信号量不再包含等待列表,而只包含信号量的值 struct tn_os_sem { char cCount; //定义用于保存信号量计数值的成员 } typedef struct tn_os_sem TN_OS_SEM; //信号量的存储空间不仅可以由操作系统分配,而且也可以由用户程序分配 //用户分配的信号量 static TN_OS_SEM __GosSem; //定义信号量 //创建信号量tnOsSemGreate()函数( tiny_os_51_core.c ) //由下可见,当任务切换且获得信号量时,信号量却并没有减1,因为此时信号量的减小是在tnOsSemPost()函数进行的 //从而保证了让我获得信号量与信号量的减小是同步的.否则,当多个任务竞争信号量时,势必会错误地获得信号量 data tnOsSemGreate ( data TN_OS_SEM *posSem, //指向信号量的指针 char cCount //声明传递信号量计数值的参数变量 ) { if ( posSem == ( data TN_OS_SEM * )0 ) { return TN_OS_PAR_ERR; //如果posSem为空指针,则返回参数错误 } posSem->cCount = cCount; //将信号量置初始值 return TN_OS_OK; //若信号量创建成功,则返回正确 } //获得信号量tnOsSemPend()函数( tiny_os_51_core.c ) char tnOsSemPend ( data TN_OS_SEM *posSem, //指向信号量变量的指针 unsigned int uiDlyTicks //等待时限 ) { unsigned char cCount; //定义传递信号量的参数变量 if ( posSem == ( data TN_OS_SEM * )0 ) { return 0; //如果posSem为空指针,返回0表明未获得信号量 } EA = 0; if ( posSem->cCount > 0 ) { posSem->cCount --; //信号量计数值减1 cCount = posSem->cCount; //取出信号量计数值并保存 EA = 1; return cCount; //返回信号量计数值后,则继续维持运行状态 } //如果信号量计数值为0,则进入等待状态,说明任务处于等待信号量的状态 __GtcbTasks[ __GthTaskCur ].uiTicks = uiDlyTicks; //等待多少时间 __GtcbTasks[ __GthTaskCur ].ucTaskStat = __TN_TASK_FLG_SEM; //任务正在等待信号量 __GtcbTasks[ __GthTaskCur ].pvEvent = ( data void * )posSem; //任务在等待这个信号量 EA = 1; __tnOsSched(); //任务切换 EA = 0; if ( __GtcbTasks[ __GthTaskCur ].ucTaskStat == __TN_TASK_FLG_RDY ) { cCount = posSem->cCount; //取出信号量 EA = 1; return cCount; //返回信号计数值后,则继续维持运行状态 } //没有等到信号量 __GtcbTasks[ __GthTask ].ucTaskStat = __TN_TASK_FLG_RDY; //任务就绪 __GtcbTasks[ __GthTask ].pvEvent = ( data void * )0; //无等待事件 EA = 1; return TN_OS_TIEM_OUT; //返回等待时间到信息,告诉用户超时 } //发送信号量tnOsSemPost(函数( tiny_os_51_core.c ) char tnOsSemPost ( data TN_OS_SEM *posSem ) { TN_OS_TASK_HANDLE tnTask; //操作的任务 if ( posSem == ( data TN_OS_SEM * )0 ) { return TN_OS_PAR_ERR; //如果posSem指针为空指针,则返回参数错误 } EA = 0; //如果posSem指针不是空指针,即少于0x7f,则信号量增加 if ( posSem->cCount < 0x7f ) //信号计数范围为0---127 { posSem->cCount ++; } //查找等待信号量的任务,判断一个任务是否等待这个信号量的方法如下: //任务必须处于等待信号量状态,即任务控制块的成员ucTaskStat的值为__TN_TASK_FLG_SEM //等待的必须是这个信号量,即任务控制块的成员pvEvent与posSem同时指向变量__GosSem for ( thTask = 0; thTask < TN_OS_MAX_TASKS; thTask ++ ) { if ( __GtcbTasks[ thTask ].ucTaskStat == __TN_TASK_FLG_SEM ) { if ( __GtcbTasks[ thTask ].pvEvent == ( data void * )posSem ) { break; } } } if ( thTask >= 0 && thTask < TN_OS_MAX_TASKS ) { //如果找到等待这个信号量的任务,则激活它 posSem->cCount --; //信号量计数值减1 __GtcbTasks[ thTask ].ucTaskStat = __TN_TASK_FLG_RDY; //任务就绪 __GtcbTasks[ thTask ].pvEvent = ( data void * )0; //无等待的事件 } if ( posSem->cCount < 0x7f ) { EA = 1; return TN_OS_OK; } EA = 1; return TN_OS_EVENT_FULL; //返回信号量计数值已满 } //删除任务( tiny_os_51_core.c ) //( 句柄为-1时删除自身,并且要转换为真实的句柄在合法范围内,才能进行任务调度 ) void tnOSTaskDel ( TN_OS_TASK_HANDLE tnTask ) { //检查参数 if ( thTask == -1 ) { thTask = __GthTaskCur; //转换为真实的句柄 if ( thTask >= TN_OS_MAX_TASKS || thTask < 0 ) //检查参数是否合法 { return; //不合法不执行 } } EA = 0; __GtcbTasks[ thTask ].ucTaskStat = __TN_TASK_FLG_DEL; //删除任务 __GtcbTasks[ thTask ].uiTicks = 0; __GtcbTasks[ thTask ].pvEvent = ( data void * )0; //无等待事件 EA = 1; if ( thTask == GthTaskCur ) //删除自身,则执行下一个任务 { __thOsSched(); } }

 

举例:

static idata unsigned char         __GucTaskStks[2][32];        //分配任务堆栈

static unsigned char     __GucTask0;        //任务0测试变量
static unsigned char     __GucTask1;        //任务1测试变量
static TN_OS_SEM         __GosSem;            //定义信号量

void task0 ( void )
{
    TMOD = ( TMOD & 0xF0 ) | 0x01;                //时钟节拍中断的初始化
    TL0 = 0x00;
    TH0 = 0x00;
    TR0 = 1;
    ET0 = 1;
    TF0 = 0;
                            //允许time0中断


    tnOsSemGreate ( &__GosSem, 0 );
    while ( 1 )
    {
        tnOsSemPend ( &__GosSem, 0 );
        __GucTask0 ++;
    }
}

void task1 ( void )
{
    while ( 1 )
    {
        __GucTask1 ++;
        tnOsSemPost ( &__GosSem );
        tnOsTimeDly ( 10 );
    }
}

void timer0ISR( void ) __interrupt 1        //时钟节拍中断服务程序
{
    tnOSTimeTick();                            //时钟节拍处理程序
}

void main ( void )
{
    tnOsInit ();
    tnOsTaskGreate ( task0, __GucTaskStks[0] );
    tnOsTaskGreate ( task1, __GucTaskStks[1] );
    tnOsStart ();
}