UCOS下的多任务框架+喂狗

        最近,在疯狂总结以前的技术栈,工作是一年比一年难找。。。此框架是用等待多个内核对象(信号量)去做任务执行的同步,用事件标志组做看门狗的任务监督。

OS_SEM	xx1_SEM, xx2_SEM;	// 信号量
OS_FLAG_GRP	WDGEventFlags;	// 事件标志组

/事件标志组-看门狗///
#define TASK1_FLAG			(1 << 0)
#define TASK2_FLAG			(1 << 1)
#define TASK3_FLAG			(1 << 2)
#define TASK_ALL_FLAG		(TASK1_FLAG | TASK2_FLAG | TASK3_FLAG)
#define TASKINIT_VALUE		0X00	

/任务优先级///
#define RESOURCES_TASK_PRIO		3
#define WDG_TASK_PRIO			4
// ucosIII支持时间片轮转:
#define TASK1_TASK_PRIO			5
#define TASK2_TASK_PRIO			5
#define TASK3_TASK_PRIO			5
// ucosII不支持时间片轮转:
//#define TASK1_TASK_PRIO			5
//#define TASK2_TASK_PRIO			6
//#define TASK3_TASK_PRIO			7

void resourcesInit_task() { 	// 资源初始化

	OS_ERR err;
	// 创建信号量,做任务同步
	OSSemCreate((OS_SEM*	)&xx1_SEM,
                 (CPU_CHAR*	)"xx1_SEM",
                 (OS_SEM_CTR)1,		
                 (OS_ERR*	)&err);

	OSSemCreate((OS_SEM*	)&xx2_SEM,
                 (CPU_CHAR*	)"xx2_SEM",
                 (OS_SEM_CTR)1,	
                 (OS_ERR*	)&err);	


	//创建一个事件标志组,作为看门狗监测
	OSFlagCreate((OS_FLAG_GRP*)&WDGEventFlags,	//指向事件标志组
                 (CPU_CHAR*	  )"Event Flags",	//名字
                 (OS_FLAGS	  )TASKINIT_VALUE,	//事件标志组初始值
                 (OS_ERR*  	  )&err);			//错误码	
	
	//删除该任务
	//OSTaskDel((OS_TCB*)&xxx_TCB,&err);
}

void xx1_task(void *p_arg) {	// 数据处理1
	CPU_SR_ALLOC();
	OS_FLAGS flag;
	OS_ERR err;
	
	while (1) {

		// 等待信号量(资源没来就会挂起去等待资源)
		OSSemPend(&xx1_SEM, 0, OS_OPT_PEND_BLOCKING, 0, &err); 
		// 进入临界区
		OS_CRITICAL_ENTER();	// OS_CFG_ISR_POST_DEFERRED_EN决定是关中断还是调度上锁来保护临界区代码
		
		// TODO:
		/* do something
			... ...		*/

		// OS_OPT_POST_1:释放信号量给等待的就绪优先级最高的任务
		OSSemPost(&xx1_SEM, OS_OPT_POST_1, &err);
		// wdg: send flag,返回值是当前EventFlags.Flags的值
		flag = OSFlagPost((OS_FLAG_GRP*)&WDGEventFlags,
						  (OS_FLAGS	   )TASK1_FLAG,
						  (OS_OPT	   )OS_OPT_POST_FLAG_SET,
						  (OS_ERR*     )&err);
		// 退出临界区
		OS_CRITICAL_EXIT();
		// 触发调度
		OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err);
	}
}

void xx2_task(void *p_arg) {	// 数据处理2
	CPU_SR_ALLOC();
	OS_FLAGS flag;
	OS_ERR err;
	
	while (1) {
		OSSemPend(&xx2_SEM, 0, OS_OPT_PEND_BLOCKING, 0, &err); 

		OS_CRITICAL_ENTER();
		
		// TODO:
		/* do something
			... ...		*/
			
		// 释放信号量	
		OSSemPost(&xx2_SEM, OS_OPT_POST_1, &err);
		// wdg
		flag = OSFlagPost((OS_FLAG_GRP*)&WDGEventFlags,
						  (OS_FLAGS	   )TASK2_FLAG,
						  (OS_OPT	   )OS_OPT_POST_FLAG_SET,
						  (OS_ERR*     )&err);		
		OS_CRITICAL_EXIT();
		
		OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err);
	}
}

void xx3_task(void *p_arg) {	// 运动控制

	CPU_SR_ALLOC();
	OS_FLAGS flag;
	OS_ERR err;
	OS_OBJ_QTY index;
	OS_PEND_DATA pend_multi_tbl[2];	
	pend_multi_tbl[0].PendObjPtr=(OS_PEND_OBJ*)&xx1_SEM;
	pend_multi_tbl[1].PendObjPtr=(OS_PEND_OBJ*)&xx2_SEM;

	while (1) {
		// 等待多个内核对象,任意一个发布都会是任务进入就绪
		// index返回就绪的对象
		index = OSPendMulti((OS_PEND_DATA*	)pend_multi_tbl,	//等待的资源列表
						  	(OS_OBJ_QTY		)2,					//等待的资源数量
						  	(OS_TICK		)0,		
						  	(OS_OPT         )OS_OPT_PEND_BLOCKING,
						  	(OS_ERR*		)&err);
		OS_CRITICAL_ENTER();
		
		// TODO:
		/* do something
			pid pd ...	*/
		
		// wdg
		flag = OSFlagPost((OS_FLAG_GRP*)&WDGEventFlags,
						  (OS_FLAGS	   )TASK3_FLAG,
						  (OS_OPT	   )OS_OPT_POST_FLAG_SET,
						  (OS_ERR*     )&err);	
		OS_CRITICAL_EXIT();
		
		// 任务调度
		OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err);
	}
}
		
void ucosTaskWDG(void* p_arg) {
	
	CPU_SR_ALLOC();
	OS_ERR err; 
	OS_FLAGS res;// CPU_INT32U

	// ucosII
	//const OS_TICK Ticks2Wait = 1/(1/OS_TICKS_PER_SEC);		
	// ucosIII,1/OSCfg_TickRate_Hz为时间片大小,此处设置1s等待节拍数,具体等待多久根据任务决定
	const OS_TICK Ticks2Wait = 1/(1/OSCfg_TickRate_Hz);	
			
    while(1)
	{
		//等待事件标志组
		res = OSFlagPend((OS_FLAG_GRP*)&WDGEventFlags,	//事件标志组
						 (OS_FLAGS	  )TASK_ALL_FLAG,	//标志事件
						 (OS_TICK     )Ticks2Wait,		//超时时间(节拍数),=0一直等待
						 (OS_OPT	  )OS_OPT_PEND_FLAG_SET_ALL+OS_OPT_PEND_FLAG_CONSUME,	//等待所有标志事件,且标志位自动清零
						 (CPU_TS*     )0,				//时间戳
						 (OS_ERR*	  )&err);			//错误码
						 
		OS_CRITICAL_ENTER();	// 看门狗作为临界区代码,别再临界区调用等待事件
		
		if((res & TASK_ALL_FLAG) == TASK_ALL_FLAG)
		{
			ucosWDG_Feed();    // 给狗粮
		} else {
			// TODO:
			// 通过变量WDGEventFlags.Flags判断哪个任务出毛病
		}
		
		OS_CRITICAL_EXIT();		
	}
}


// 传感器1接的中断线
void xx1_IRQHandler() {			// 数据采集1

    OSIntEnter();//中断嵌套次数OSIntNesting计数+1

	// 可以使用定时器计数值降低中断实际采集频率
	if (cnt>=n) {
		
		// TODO:
		/* do something
			... ...		*/
	} else {
		NULL;
	}

	OSIntExit();//中断嵌套次数OSIntNesting计数-1
}

// 传感器2接的中断线
void xx2_IRQHandler() {			// 数据采集2

    OSIntEnter();

	if (cnt2>=n2) {
		
		// TODO:
		/* do something
			... ...		*/		
	} else {
		NULL;
	}

	OSIntExit(); 
}

        关于看门狗任务优先级问题:总之有个原则,在看门狗门限内,所有被监控任务都要跑一次。对于系统中优先级高于看门狗的任务,要保证这些高优先级任务不能长期处于运行态,适当的给出任务调度指令。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值