OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 7672|回复: 4

原子哥的任务启动方式分析

[复制链接]

12

主题

71

帖子

0

精华

初级会员

Rank: 2

积分
157
金钱
157
注册时间
2015-1-28
在线时间
8 小时
发表于 2015-3-12 12:01:52 | 显示全部楼层 |阅读模式
5金钱
先上代码(原子哥的“探索者-任务调度实验代码”):

//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操作系统的,这个系统内核会创建一个启动任务,这个任务的优先级是系统最高的,我们只需在启动任务创建自己的任务就行了。


最佳答案

查看完整内容[请看2#楼]

你说的没错,可以将start_task的任务优先级调高,临界代码段保护最好的方式确实是信号量,但是有时候信号量也没用的,比如从外部SRAM中读取数据,最好不要被中断打断,这时候就可以使用OS_ENTER_CRITICAL()来关闭全局中断,数据读取完成后在打开中断。
持续而安静地投入
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

88

主题

7377

帖子

5

精华

资深版主

Rank: 8Rank: 8

积分
14980
金钱
14980
注册时间
2013-11-13
在线时间
1823 小时
发表于 2015-3-12 12:01:53 | 显示全部楼层
你说的没错,可以将start_task的任务优先级调高,临界代码段保护最好的方式确实是信号量,但是有时候信号量也没用的,比如从外部SRAM中读取数据,最好不要被中断打断,这时候就可以使用OS_ENTER_CRITICAL()来关闭全局中断,数据读取完成后在打开中断。
开往春天的手扶拖拉机
回复

使用道具 举报

12

主题

71

帖子

0

精华

初级会员

Rank: 2

积分
157
金钱
157
注册时间
2015-1-28
在线时间
8 小时
 楼主| 发表于 2015-3-12 17:02:05 | 显示全部楼层
回复【2楼】zuozhongkai:
---------------------------------
这个我不知道哦,刚开始使用stm32。不过我的项目刚好使用到了外部SRAM,有些搞不懂,顺便请教一下。原子哥推荐的使用外部sram的方式是在申请数组时指定到外部sram的地址,那你的意思是在使用这个数组的时候要把中断关掉?是这样理解吗?
持续而安静地投入
回复

使用道具 举报

88

主题

7377

帖子

5

精华

资深版主

Rank: 8Rank: 8

积分
14980
金钱
14980
注册时间
2013-11-13
在线时间
1823 小时
发表于 2015-3-12 17:32:50 | 显示全部楼层
回复【3楼】磨剑:
---------------------------------
我们推荐的使用SRAM的方式是动态内存管理,使用mymlloc()函数来申请的,在使用这个数组的时候,最好关闭中断,防止操作的时候被中断打断导致操作出错
开往春天的手扶拖拉机
回复

使用道具 举报

12

主题

71

帖子

0

精华

初级会员

Rank: 2

积分
157
金钱
157
注册时间
2015-1-28
在线时间
8 小时
 楼主| 发表于 2015-3-12 17:56:26 | 显示全部楼层
回复【4楼】zuozhongkai:
---------------------------------
嗯,明白了,我看了下代码,这里使用OS_ENTER_CRITICAL()处理临界区的访问。如果没有人在中断服务程序里面使用mymalloc(),信号量与OS_ENTER_CRITICAL()的效果是一样的;如果有人可能在中断服务程序里面使用mymalloc(),那么必须使用OS_ENTER_CRITICAL()。不过一般不会有人在中断服务程序干这个事吧
持续而安静地投入
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-4-19 21:39

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表