最近,在疯狂总结以前的技术栈,工作是一年比一年难找。。。此框架是用等待多个内核对象(信号量)去做任务执行的同步,用事件标志组做看门狗的任务监督。
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();
}
关于看门狗任务优先级问题:总之有个原则,在看门狗门限内,所有被监控任务都要跑一次。对于系统中优先级高于看门狗的任务,要保证这些高优先级任务不能长期处于运行态,适当的给出任务调度指令。