9-钩子函数(介入函数)

UCOSIII 钩子函数(介入函数)

 

 

UCOSIII的钩子函数有8个,有些书籍会翻译为介入函数,其实是同一个意思。什么是钩子函数呢,也许是因为函数名字直译过来就是钩子吧。具体作用还真的不好定义,还不如直接看这几个函数的具体功能作用来得快。

在介绍具体的钩子函数前,先介绍下钩子函数的初始化函数,这个初始化函数可以一次性对所有钩子函数进行初始化,函数原型如下;

void  App_OS_SetAllHooks (void)

{

#if OS_CFG_APP_HOOKS_EN > 0u

    CPU_SR_ALLOC();

 

 

    CPU_CRITICAL_ENTER();

    OS_AppTaskCreateHookPtr = App_OS_TaskCreateHook;

    OS_AppTaskDelHookPtr    = App_OS_TaskDelHook;

    OS_AppTaskReturnHookPtr = App_OS_TaskReturnHook;

 

    OS_AppIdleTaskHookPtr   = App_OS_IdleTaskHook;

    OS_AppStatTaskHookPtr   = App_OS_StatTaskHook;

    OS_AppTaskSwHookPtr     = App_OS_TaskSwHook;

    OS_AppTimeTickHookPtr   = App_OS_TimeTickHook;

    CPU_CRITICAL_EXIT();

#endif

}

可以看到,只有使能了钩子函数后,这个初始化函数才会对钩子函数进行初始化。同一功能的钩子函数其实是有两个钩子函数组成,其中一个是给UCOS移植者使用,另外一个是给UCOS应用开发者使用,而这个初始化函数就是把UCOS移植者的函数和应用开发者的函数绑定在一起。同一功能的两个钩子函数其实很有规律的,这两者的名字是很相近的,只是应用开发者的钩子函数多了个APP开头,具体看下表;

 

移植者使用的钩子函数

应用开发者使用的钩子函数

空闲任务钩子函数

void  OSIdleTaskHook (void)

void  App_OS_IdleTaskHook (void)

系统初始化钩子函数

void  OSInitHook (void)

任务创建钩子函数

void  OSTaskCreateHook (OS_TCB  *p_tcb)

void  App_OS_TaskCreateHook (OS_TCB  *p_tcb)

任务删除钩子函数

void  OSTaskDelHook (OS_TCB  *p_tcb)

void  App_OS_TaskDelHook (OS_TCB  *p_tcb)

任务意外返回钩子函数

void  OSTaskReturnHook (OS_TCB  *p_tcb)

void  App_OS_TaskReturnHook (OS_TCB  *p_tcb)

任务开始运行钩子函数

void  OSStatTaskHook (void)

void  App_OS_StatTaskHook (void)

任务切换钩子函数

void  OSTaskSwHook (void)

void  App_OS_TaskSwHook (void)

软件定时器节拍钩子函数

void  OSTimeTickHook (void)

void  App_OS_TimeTickHook (void)

 

 

  1. 空闲任务钩子函数

在系统不执行其他任务的时候,也就是开发者所建立的任务全都被挂起来的时候,CPU总不能停止吧,所以这个时候系统就来执行空闲任务了,而空闲任务里也可以做一些无关紧要的事情,这些无关紧要的事情的代码就写在空闲任务钩子函数里面。当CPU很忙的时候就很少执行空闲任务钩子函数的代码,当CPU不忙的时候空闲任务钩子函数执行的次数就多一些。当然,如果为了省电也可以在空闲任务钩子函数里让CPU进入休眠态,不过进入休眠后得有个唤醒的方式,可以是周期性的唤醒,也可以是外部中断唤醒,这个的看具体的芯片。

函数原型;

void  OSIdleTaskHook (void)

{

#if OS_CFG_APP_HOOKS_EN > 0u

    if (OS_AppIdleTaskHookPtr != (OS_APP_HOOK_VOID)0) {

        (*OS_AppIdleTaskHookPtr)();

    }

#endif

}

很明显有个使能开关OS_CFG_APP_HOOKS_EN,要使用空闲任务钩子函数的话就得打开这个使能开关。从代码可以看到,这个函数里面有一个OS_AppIdleTaskHookPtr,这玩意经过几个传递后最终指向void  App_OS_IdleTaskHook (void)这个函数,找到这个void  App_OS_IdleTaskHook (void)函数的定义可以看到,这个函数是空的,我们的空闲任务代码就写在这个函数里面。至于说为什么不直接在void  OSIdleTaskHook (void)里面写空闲任务的代码,而是在void  App_OS_IdleTaskHook (void)这个函数里写呢,也许是为了让空闲任务的代码看起来更清晰吧。

这个章节带了一个软件例程,看了例程应该就知道空闲任务可以干嘛了,例程在文章的最后面。

 

  1. 系统初始化钩子函数 void  OSInitHook (void)

在系统初始化的时候除了要对系统进行初始化外,我们也可以在系统初始化的过程中做一些我们想要做的事情,我们在这个时候要做的事情就写在系统初始化钩子函数里,其实一般只有在移植UCOS的时候才会用到这个钩子函数,毕竟不同的芯片有些寄存器是不一样的。但是在系统移植完成后,在写应用任务的时候一般不会在用到这个钩子函数了,其实这个钩子函数是给UCOS的移植人员用的,并不是给UCOS的应用开发者用的。使用这个系统初始化钩子函数的话,我们的代码直接写在这个函数里就好。

 

  1. 任务创建钩子函数 void  OSTaskCreateHook (OS_TCB  *p_tcb)

这个钩子函数是在我们创建任务的时候调用的,可以把创建任务时要做的其他事情写在任务创建的钩子函数里。其实这个钩子函数是给UCOS的移植人员用的,并不是给UCOS的应用开发者用的。void  OSTaskCreateHook (OS_TCB  *p_tcb)是给移植者用的,应用开发者要使用这个函数的话代码应该写在void  App_OS_TaskCreateHook (OS_TCB  *p_tcb)这个函数里的。

 

  1. 任务删除钩子函数void  OSTaskDelHook (OS_TCB  *p_tcb)

既然有创建任务的钩子函数,那么当然也有任务删除的钩子函数了。在任务被删除后系统会调用这个钩子函数,估计是做一些释放内存之类的事情吧,这个钩子函数也是给UCOS的移植人员用的。应用开发者要使用这个函数的话代码应该写在void  App_OS_TaskDelHook (OS_TCB  *p_tcb)这个函数里。

 

  1. 任务意外返回钩子函数 void  OSTaskReturnHook (OS_TCB  *p_tcb)

任务按理说是一个无限循环,永远不会返回,但是当发生意外的时候还是有可能会返回 ,当意外返回的时候就执行这个钩子函数,具体这个函数里面需要干写什么事情呢,据说这个函数是给UCOS移植者用的,不是给应用开发者用的,所以暂时不纠结这个该怎么用。说白了就是我也不知道怎么用。应用开发者要使用这个函数的话代码应该写在void  App_OS_TaskReturnHook (OS_TCB  *p_tcb)里面。

 

  1. 任务开始运行钩子函数 void  OSStatTaskHook (void)

这玩意也是给UCOS移植者用的,暂时不纠结功能和用法。应用开发者要使用这个函数的话代码应该写在在void  App_OS_StatTaskHook (void)里面。

 

  1. 任务切换钩子函数 void  OSTaskSwHook (void)

每次任务切换的时候都会调用这个钩子函数,但是上面这个钩子函数是给移植者用的,应用开发者的钩子函数代码应该写在void  App_OS_TaskSwHook (void)里面。

  1. 软件定时器节拍钩子函数 void  OSTimeTickHook (void)

从函数名可以很容易的看出来,软件定时器每来一个节拍就调用一次这个函数,可以在这个钩子函数里执行周期性的事情,周期还特别稳定。同理,这个函数也是给移植者用的,应用开发者应该用下面的这个钩子函数void  App_OS_TimeTickHook (void)。

 

来个栗子吧,这个栗子是针对空闲任务钩子函数的,另外几个钩子函数就不写工程了。要使用空闲任务钩子函数很简单,可以分为以下几个步骤;

  1. 打开钩子函数使能开关 OS_CFG_APP_HOOKS_EN
  2. 对钩子函数进行初始化 App_OS_SetAllHooks();
  3. 在App_OS_IdleTaskHook()函数里写想让空闲任务干的事情

 

这个工程实现的功能很简单,一共两个任务,一个任务控制LED闪烁提示系统运行,另外一个是串口任务。定义一个全局变量testCount,这个变量在空闲任务钩子函数里面累加,每隔一秒钟就在串口任务中输出这个变量的值,然后清零,就看看每秒钟这个值能累加到多少。我用的STM32运行在72m主频,系统滴答频率为200hz,testCount每秒钟能累加到974194左右,这个一个浮动的值,但是波动不大,只有正负10这样子。很明显这个累加值比系统节拍大很多,所以运行一次空闲任务的话空闲任务钩子函数会运行多次。代码如下

Main.c文件
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "includes.h"

#include "task.h"
/************************************************
 ALIENTEK战舰STM32开发板UCOS实验
 技术支持:www.openedv.com
 淘宝店铺:http://eboard.taobao.com 
 关注微信公众平台微信号:"正点原子",免费获取STM32资料。
 广州市星翼电子科技有限公司  
 作者:正点原子 @ALIENTEK
************************************************/

//UCOSIII中以下优先级用户程序不能使用,ALIENTEK
//将这些优先级分配给了UCOSIII的5个系统内部任务
//优先级0:中断服务服务管理任务 OS_IntQTask()
//优先级1:时钟节拍任务 OS_TickTask()
//优先级2:定时任务 OS_TmrTask()
//优先级OS_CFG_PRIO_MAX-2:统计任务 OS_StatTask()
//优先级OS_CFG_PRIO_MAX-1:空闲任务 OS_IdleTask()
//技术支持:www.openedv.com
//淘宝店铺:http://eboard.taobao.com  
//广州市星翼电子科技有限公司  
//作者:正点原子 @ALIENTEK


//*****************************************************************
//开始任务
OS_TCB  starTaskTCB;	//任务控制块
#define STAR_TASK_PRIO      3		//任务优先级
#define STAR_TASK_STK_SIZE  128	//任务堆栈总大小
CPU_STK STAR_TASK_STK[ STAR_TASK_STK_SIZE ];	//任务堆栈数组


int main()
{
	OS_ERR myErr;			//os的错误码
	CPU_SR_ALLOC();	//使用临街保护就得添加这玩意,不然会报错
	
	delay_init();  //时钟初始化
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断分组配置
	uart_init(115200);   //串口初始化
	LED_Init();        	 //LED初始化	
	
	OSInit(&myErr);				 //os初始化
	
	//创建任务的时候进入临街保护比较好,但是这个函数非用户的API函数,用户使用是否合适以后再讨论
	OS_CRITICAL_ENTER(); 
	
	//创建开始任务,在开始任务里创建其他任务,为每个函数入口参数都强制转换类型吧,以防万一
	OSTaskCreate (		(OS_TCB       *)&starTaskTCB,						//任务控制块,
                    (CPU_CHAR     *)"star task",						//任务名字
                    (OS_TASK_PTR   )starTaskFunc,						//任务函数
                    (void         *)0,											//任务函数入口参数
                    (OS_PRIO       )STAR_TASK_PRIO,					//任务优先级
                    (CPU_STK      *)&STAR_TASK_STK[0],			//堆栈数组基地址
                    (CPU_STK_SIZE  ) STAR_TASK_STK_SIZE/10,	//堆栈溢出限位
                    (CPU_STK_SIZE  ) STAR_TASK_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       *)&myErr);								//错误码
	
 OS_CRITICAL_EXIT();	//任务创建完了就该退出临界保护了									
 OSStart(&myErr);				//任务创建完成后就该运行了
 while(1);						//运行系统后就一直在系统里面跑了,应该运行不到这里
}

Task.c文件
#include "task.h"
#include "sys.h"
#include "led.h"
#include "includes.h" //想要使用UCOS系统,得包含这个头文件
#include "os_app_hooks.h"
			
	
	
u32 testCount=0;

//LED秒闪任务,提示系统正在运行
OS_TCB  ledTaskTCB;
#define LED_TASK_PRIO 4
#define LED_TASK_STK_SIZE 128
CPU_STK LED_TASK_STK[LED_TASK_STK_SIZE];

//串口输出任务1
OS_TCB  uartTask_1_TCB;
#define UART_TASK_1_PRIO 5
#define UART_TASK_1_STK_SIZE 128
CPU_STK UART_TASK_1_STK[ UART_TASK_1_STK_SIZE ];



void starTaskFunc()
{	
	OS_ERR myErr;
	
	App_OS_SetAllHooks();//钩子函数初始化
	
	OSTaskCreate (	  (OS_TCB       *)&ledTaskTCB,
                    (CPU_CHAR     *)"led task",
                    (OS_TASK_PTR   )ledTaskFunc,
                    (void         *)0,
                    (OS_PRIO       )LED_TASK_PRIO,
                    (CPU_STK      *)&LED_TASK_STK[0],
                    (CPU_STK_SIZE  ) LED_TASK_STK_SIZE/10,
                    (CPU_STK_SIZE  ) LED_TASK_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       *)&myErr);

										
	OSTaskCreate (	  (OS_TCB       *)&uartTask_1_TCB,
                    (CPU_CHAR     *)"uart task 1 ",
                    (OS_TASK_PTR   )uartTask_1_Func,
                    (void         *)0,
                    (OS_PRIO       )UART_TASK_1_PRIO,
                    (CPU_STK      *)&UART_TASK_1_STK[0],
                    (CPU_STK_SIZE  ) UART_TASK_1_STK_SIZE/10,
                    (CPU_STK_SIZE  ) UART_TASK_1_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       *)&myErr);
	
	
//这个任务只是用来创建其他任务的,其他任务创建完成了这个任务也就没用了,删除掉		
	OSTaskDel((OS_TCB*)0,&myErr);
}	

//LED任务的任务函数
//LED每隔500ms翻转一次,提示系统正在运行
void ledTaskFunc()
{
	OS_ERR myErr;
	while(1)		//注意,每个任务都是一个死循环
	{
		OSTimeDlyHMSM (		 (CPU_INT16U  ) 0,		//时
											 (CPU_INT16U  ) 0,		//分
											 (CPU_INT16U  ) 0,		//秒
											 (CPU_INT32U  ) 100,	//毫秒
											 (OS_OPT      ) OS_OPT_TIME_HMSM_STRICT,	//选项
											 (OS_ERR      *)&myErr);	//错误码
		LED = !LED;	//LED状态翻转
		
	}	
}

//串口任务1的任务函数
//功能;每隔1秒向电脑串口助手发送一次数据
void uartTask_1_Func()
{
	OS_ERR myErr;
	while(1)
	{
		OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_HMSM_STRICT,&myErr);//延时1秒

		printf("testCount=%d\r\n",testCount);
		testCount=0;
	}
}

	
Task.h文件
#ifndef __TASK_H
#define __TASK_H	
#include "sys.h"

extern  u32 testCount;//定义为全局变量
	 				    
void starTaskFunc();	
void ledTaskFunc();
void uartTask_1_Func();							
#endif

os_app_hooks.c文件
这个文件里面有很多函数,但是我值用到一个函数,这里就只把用到的代码粘贴出来,没用到的就不粘贴了。
void  App_OS_IdleTaskHook (void)
{
	testCount++;
}


 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值