先上代码(原子哥的“探索者-任务调度实验代码”):
//START 任务
//设置任务优先级
#define START_TASK_PRIO 10 //开始任务的优先级设置为最低
//设置任务堆栈大小
#define START_STK_SIZE 64
//任务堆栈
OS_STK START_TASK_STK[START_STK_SIZE];
//任务函数
void start_task(void *pdata);
//LED0任务
//设置任务优先级
#define LED0_TASK_PRIO 7
//设置任务堆栈大小
#define LED0_STK_SIZE 64
//任务堆栈
OS_STK LED0_TASK_STK[LED0_STK_SIZE];
//任务函数
void led0_task(void *pdata);
//LED1任务
//设置任务优先级
#define LED1_TASK_PRIO 6
//设置任务堆栈大小
#define LED1_STK_SIZE 64
//任务堆栈
OS_STK LED1_TASK_STK[LED1_STK_SIZE];
//任务函数
void led1_task(void *pdata);
int main(void)
{
delay_init(168); //初始化延时函数
LED_Init(); //初始化LED端口
OSInit();
OSTaskCreate(start_task,(void *)0,(OS_STK *)&START_TASK_STK[START_STK_SIZE-1],START_TASK_PRIO );//创建起始任务
OSStart();
}
//开始任务
void start_task(void *pdata)
{
OS_CPU_SR cpu_sr=0;
pdata = pdata;
OS_ENTER_CRITICAL(); //进入临界区(无法被中断打断)
OSTaskCreate(led0_task,(void *)0,(OS_STK*)&LED0_TASK_STK[LED0_STK_SIZE-1],LED0_TASK_PRIO);
OSTaskCreate(led1_task,(void *)0,(OS_STK*)&LED1_TASK_STK[LED1_STK_SIZE-1],LED1_TASK_PRIO);
OSTaskSuspend(START_TASK_PRIO); //挂起起始任务.
OS_EXIT_CRITICAL(); //退出临界区(可以被中断打断)
}
//LED0任务
void led0_task(void *pdata)
{
while(1)
{
LED0=0;
delay_ms(80);
LED0=1;
delay_ms(920);
};
}
//LED1任务
void led1_task(void *pdata)
{
while(1)
{
LED1=0;
delay_ms(300);
LED1=1;
delay_ms(300);
};
}
主要逻辑:首先创建start_task任务,然后在start_task任务里面创建led0_task和led1_task任务。start_task任务优先级比led0_task和led1_task任务低。
我有以下几点看法:
一, OS_ENTER_CRITICAL()与 OS_EXIT_CRITICAL()的使用。
1,这一对宏主要作用是用来保护临界代码,但是这里使用的时候并没有涉及到临界代码(操作系统函数内部的临界代码不算,因为它自己做了处理),并没有起到保护临界代码的作用,实际上起的作用是防止任务切换(阻止pendSV中断)。为什么呢?因为在调用OSTaskCreate创建led0_task和led1_task任务时,由于它们的优先级比start_task高,会进行任务切换,会触发pendSV中断异常,但是不会进入中断,因为OS_ENTER_CRITICAL()已经把中断关闭了。可以通过断点调试实验下。
2,当需要保护临界代码时,也不推荐使用这对宏,因为这一对宏主要是在ucos内核中使用,在用户程序中要谨慎使用(邵贝贝的《嵌入式实时操作系统ucos-II》中74页有说明),保护临界代码更好的方式是使用信号量。
二,我认为的更好的任务启动方式。
让启动任务start_task的优先级比其他任务优先级高,这样在原子哥的代码的基础上,把OS_ENTER_CRITICAL()与 OS_EXIT_CRITICAL()这一对宏去掉就行了。我是参考vxworks操作系统的,这个系统内核会创建一个启动任务,这个任务的优先级是系统最高的,我们只需在启动任务创建自己的任务就行了。
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
一周热门 更多>