OpenEdv-开源电子网

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

UCOSIII中,2个任务都操作某个硬件,会不会冲突?

[复制链接]

55

主题

142

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
375
金钱
375
注册时间
2013-1-18
在线时间
56 小时
发表于 2015-7-22 15:41:53 | 显示全部楼层 |阅读模式
5金钱
在UCOSIII中,1个任务正操作某个硬件,被另1个任务打断,另1个任务也操作此硬件,会不会冲突?

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

39

主题

598

帖子

0

精华

高级会员

Rank: 4

积分
875
金钱
875
注册时间
2013-12-18
在线时间
41 小时
发表于 2015-7-22 15:44:57 | 显示全部楼层
回复

使用道具 举报

22

主题

2251

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4471
金钱
4471
注册时间
2013-4-22
在线时间
335 小时
发表于 2015-7-22 15:58:00 | 显示全部楼层
不会。。。。
回复

使用道具 举报

55

主题

142

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
375
金钱
375
注册时间
2013-1-18
在线时间
56 小时
 楼主| 发表于 2015-7-22 16:01:21 | 显示全部楼层
//task1任务函数
void task1_task(void *p_arg)
{
u16 i;
u8 task1_num=0;
OS_ERR err;
CPU_SR_ALLOC();
p_arg = p_arg;

POINT_COLOR = BLACK;
OS_CRITICAL_ENTER();
LCD_DrawRectangle(5,110,115,314);  //画一个矩形
LCD_DrawLine(5,130,115,130); //画线
POINT_COLOR = BLUE;
LCD_ShowString(6,111,110,16,16,"Task1 Run:000");
OS_CRITICAL_EXIT();

while(1)
{
task1_num++; //任务执1行次数加1 注意task1_num1加到255的时候会清零!!
LED0= ~LED0;
printf("任务1已经执行:%d次\r\n",task1_num);

// if(task1_num==5) 
// {
// OSTaskDel((OS_TCB*)&Task2_TaskTCB,&err); //任务1执行5此后删除掉任务2
// printf("任务1删除了任务2!\r\n");
// }

for(i=0;i<100;i++)
{
LCD_Fill(6,131,114,313,lcd_discolor[task1_num%14]);  //填充区域
LCD_ShowxNum(86,111,task1_num,3,16,0x80); //显示任务执行次数
OSTimeDlyHMSM(0,0,0,10,OS_OPT_TIME_HMSM_STRICT,&err);  //延时1s
}
}
}
回复

使用道具 举报

55

主题

142

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
375
金钱
375
注册时间
2013-1-18
在线时间
56 小时
 楼主| 发表于 2015-7-22 16:01:37 | 显示全部楼层
//task2任务函数
void task2_task(void *p_arg)
{
u16 i;
u8 task2_num=0;
OS_ERR err;
CPU_SR_ALLOC();
p_arg = p_arg;

POINT_COLOR = BLACK;
OS_CRITICAL_ENTER();
LCD_DrawRectangle(125,110,234,314); //画一个矩形
LCD_DrawLine(125,130,234,130); //画线
POINT_COLOR = BLUE;
LCD_ShowString(126,111,110,16,16,"Task2 Run:000");
OS_CRITICAL_EXIT();
while(1)
{
task2_num++; //任务2执行次数加1 注意task1_num2加到255的时候会清零!!
LED1=~LED1;
printf("任务2已经执行:%d次\r\n",task2_num);

for(i=0;i<1000;i++)
{
LCD_ShowxNum(206,111,task2_num,3,16,0x80);  //显示任务执行次数
LCD_Fill(126,131,233,313,lcd_discolor[13-task2_num%14]); //填充区域

OSTimeDlyHMSM(0,0,0,1,OS_OPT_TIME_HMSM_STRICT,&err); 
}

}
}
回复

使用道具 举报

55

主题

142

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
375
金钱
375
注册时间
2013-1-18
在线时间
56 小时
 楼主| 发表于 2015-7-22 16:01:58 | 显示全部楼层
//任务优先级
#define TASK1_TASK_PRIO 4
//任务堆栈大小
#define TASK1_STK_SIZE  128
//任务控制块
OS_TCB Task1_TaskTCB;
//任务堆栈
CPU_STK TASK1_TASK_STK[TASK1_STK_SIZE];
void task1_task(void *p_arg);

//任务优先级
#define TASK2_TASK_PRIO 5
//任务堆栈大小
#define TASK2_STK_SIZE  128
//任务控制块
OS_TCB Task2_TaskTCB;
//任务堆栈
CPU_STK TASK2_TASK_STK[TASK2_STK_SIZE];
//任务函数
void task2_task(void *p_arg);
回复

使用道具 举报

81

主题

1002

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1876
金钱
1876
注册时间
2014-9-10
在线时间
208 小时
发表于 2015-7-22 16:04:40 | 显示全部楼层
不知道。
咱来谈谈理论, 纯靠想象的话:
我觉得不能这样搞,应该会有影响。
一个任务a操作硬件时,另一个任务b不能在a处理完之前去折腾这个硬件。
估计会被玩死的吧...
小小蜗牛
回复

使用道具 举报

55

主题

142

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
375
金钱
375
注册时间
2013-1-18
在线时间
56 小时
 楼主| 发表于 2015-7-22 16:06:47 | 显示全部楼层
结果是冲突的。见图片。
冲突.bmp
回复

使用道具 举报

55

主题

142

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
375
金钱
375
注册时间
2013-1-18
在线时间
56 小时
 楼主| 发表于 2015-7-22 16:09:52 | 显示全部楼层
在2个任务中,涉及到同一个硬件,要小心!  怎样合理安排任务,非常重要。系统越复杂,失控可能性越大。
回复

使用道具 举报

8

主题

98

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
210
金钱
210
注册时间
2014-9-29
在线时间
13 小时
发表于 2015-7-22 16:15:50 | 显示全部楼层
应该会有冲突,因为一个任务在操作硬件时应该不能被打断,它不像软件可以中断嵌套,可以保存现场,恢复现场,继续执行,硬件的打断也许是不允许发生的,是不可逆转的,应该最好加入临界区,使之不被任何中断打断,操作硬件时应该关闭所有中断,操作完成后再打开中断,否则,可能会出现一些不可预料的结果的。
回复

使用道具 举报

55

主题

142

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
375
金钱
375
注册时间
2013-1-18
在线时间
56 小时
 楼主| 发表于 2015-7-22 16:51:11 | 显示全部楼层
//task1任务函数
void task1_task(void *p_arg)
{
u16 i;
u8 task1_num=0;
OS_ERR err;
CPU_SR_ALLOC();
p_arg = p_arg;

POINT_COLOR = BLACK;
OS_CRITICAL_ENTER();
LCD_DrawRectangle(5,110,115,314); //画一个矩形
LCD_DrawLine(5,130,115,130); //画线
POINT_COLOR = BLUE;
LCD_ShowString(6,111,110,16,16,"Task1 Run:000");
OS_CRITICAL_EXIT();

while(1)
{
task1_num++; //任务执1行次数加1 注意task1_num1加到255的时候会清零!!
LED0= ~LED0;
printf("任务1已经执行:%d次\r\n",task1_num);

// if(task1_num==5) 
// {
// OSTaskDel((OS_TCB*)&Task2_TaskTCB,&err); //任务1执行5此后删除掉任务2
// printf("任务1删除了任务2!\r\n");
// }

for(i=0;i<100;i++)
{
OS_CRITICAL_ENTER();
LCD_Fill(6,131,114,313,lcd_discolor[task1_num%14]); //填充区域
LCD_ShowxNum(86,111,task1_num,3,16,0x80); //显示任务执行次数
OS_CRITICAL_EXIT();
OSTimeDlyHMSM(0,0,0,10,OS_OPT_TIME_HMSM_STRICT,&err); //延时1s
}
}
}

//task2任务函数
void task2_task(void *p_arg)
{
u16 i;
u8 task2_num=0;
OS_ERR err;
CPU_SR_ALLOC();
p_arg = p_arg;

POINT_COLOR = BLACK;
OS_CRITICAL_ENTER();
LCD_DrawRectangle(125,110,234,314); //画一个矩形
LCD_DrawLine(125,130,234,130); //画线
POINT_COLOR = BLUE;
LCD_ShowString(126,111,110,16,16,"Task2 Run:000");
OS_CRITICAL_EXIT();
while(1)
{
task2_num++; //任务2执行次数加1 注意task1_num2加到255的时候会清零!!
LED1=~LED1;
printf("任务2已经执行:%d次\r\n",task2_num);

for(i=0;i<1000;i++)
{
OS_CRITICAL_ENTER();
LCD_ShowxNum(206,111,task2_num,3,16,0x80);  //显示任务执行次数
LCD_Fill(126,131,233,313,lcd_discolor[13-task2_num%14]); //填充区域
OS_CRITICAL_EXIT();
OSTimeDlyHMSM(0,0,0,1,OS_OPT_TIME_HMSM_STRICT,&err); 
}
}
}

回复

使用道具 举报

55

主题

142

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
375
金钱
375
注册时间
2013-1-18
在线时间
56 小时
 楼主| 发表于 2015-7-22 16:51:49 | 显示全部楼层
"加入临界区",有效果。显示正常了!
回复

使用道具 举报

88

主题

7377

帖子

5

精华

资深版主

Rank: 8Rank: 8

积分
14980
金钱
14980
注册时间
2013-11-13
在线时间
1823 小时
发表于 2015-7-22 16:53:08 | 显示全部楼层
两个任务要操作同一个硬件外设这个问题就是典型的共享资源保护的问题!对于共享资源的保护你可以使用临界段代码保护的方式也可以使用信号量。
开往春天的手扶拖拉机
回复

使用道具 举报

55

主题

142

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
375
金钱
375
注册时间
2013-1-18
在线时间
56 小时
 楼主| 发表于 2015-7-22 17:02:05 | 显示全部楼层
http://blog.csdn.net/liuhui_8989/article/details/8783323
回复

使用道具 举报

55

主题

142

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
375
金钱
375
注册时间
2013-1-18
在线时间
56 小时
 楼主| 发表于 2015-7-22 17:03:54 | 显示全部楼层
"使用信号量"比较可靠!,“临界段代码保护”还有风险!同样是通过关中断来保护临界区,OS_ENTER_CRITICAL/OS_EXIT_CRITICAL一共实现了三种实现方式。 第一种方式,OS_ENTER_CRITICAL()简单地关中断,OS_EXIT_CRITICAL()简单地开中断。这种方式虽然简单高效,但无法满足嵌套的情况。如果有两层临界区保护,在退出内层临界区时就会开中断,使外层的临界区也失去保护。虽然ucos的内核写的足够好,没有明显嵌套临界区的情况,但谁也无法保证一定没有,无法保证今后没有,无法保证在附加的驱动或什么位置没有,所以基本上第一种方法是没有人用的。
   第二种方式,OS_ENTER_CRITICAL()会在关中断前保存之前的标志寄存器内容到堆栈中,OS_EXIT_CRITICAL()从堆栈中恢复之前保存的状态。这样就允许了临界区嵌套的情况。但现在看来,这种方法还存在很大的问题,甚至会出现致命的漏洞。
回复

使用道具 举报

55

主题

142

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
375
金钱
375
注册时间
2013-1-18
在线时间
56 小时
 楼主| 发表于 2015-7-22 17:09:29 | 显示全部楼层
在使用UCOSIII时,要确保理论上无问题,否则不敢用。
回复

使用道具 举报

55

主题

142

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
375
金钱
375
注册时间
2013-1-18
在线时间
56 小时
 楼主| 发表于 2015-7-22 17:43:51 | 显示全部楼层
//任务优先级
#define START_TASK_PRIO 3
//任务堆栈大小
#define START_STK_SIZE  128
//任务控制块
OS_TCB StartTaskTCB;
//任务堆栈
CPU_STK START_TASK_STK[START_STK_SIZE];
//任务函数
void start_task(void *p_arg);

//任务优先级
#define TASK1_TASK_PRIO 4
//任务堆栈大小
#define TASK1_STK_SIZE  128
//任务控制块
OS_TCB Task1_TaskTCB;
//任务堆栈
CPU_STK TASK1_TASK_STK[TASK1_STK_SIZE];
void task1_task(void *p_arg);

//任务优先级 5
#define TASK2_TASK_PRIO 5
//任务堆栈大小
#define TASK2_STK_SIZE  128
//任务控制块
OS_TCB Task2_TaskTCB;
//任务堆栈
CPU_STK TASK2_TASK_STK[TASK2_STK_SIZE];
//任务函数
void task2_task(void *p_arg);

//LCD刷屏时使用的颜色
int lcd_discolor[14]=
{
WHITE, BLACK, BLUE,  BRED,      
GRED,  GBLUE, RED,   MAGENTA,         
GREEN, CYAN,  YELLOW,BROWN, 
BRRED, GRAY 
};


u8 cnt;

OS_MUTEX TEST_MUTEX; //定义一个互斥信号量

int main(void)

OS_ERR err;
CPU_SR_ALLOC();   //临界代码保护开始

cnt=0;

delay_init(168);     //初始化延时函数
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断分组配置
uart_init(115200);   //串口初始化
LED_Init();     //初始化LED端口
BEEP_Init();          //初始化蜂鸣器端口
LCD_Init();


POINT_COLOR = RED;
LCD_ShowString(30,10,200,16,16,"Explorer STM32F4");
LCD_ShowString(30,30,200,16,16,"UCOSIII Examp 6-1");
LCD_ShowString(30,50,200,16,16,"Task Creat and Del");
LCD_ShowString(30,70,200,16,16,"ATOM@ALIENTEK");
LCD_ShowString(30,90,200,16,16,"2015/07/22");
 
 
OSInit(&err);     //初始化UCOSIII
OS_CRITICAL_ENTER(); //进入临界区  
//创建开始任务
OSTaskCreate((OS_TCB  * )&StartTaskTCB, //任务控制块
 (CPU_CHAR * )"start task",  //任务名字
                 (OS_TASK_PTR )start_task,  //任务函数
                 (void * )0, //传递给任务函数的参数
                 (OS_PRIO   )START_TASK_PRIO,     //任务优先级
                 (CPU_STK   * )&START_TASK_STK[0], //任务堆栈基地址
                 (CPU_STK_SIZE)START_STK_SIZE/10, //任务堆栈深度限位
                 (CPU_STK_SIZE)START_STK_SIZE, //任务堆栈大小
                 (OS_MSG_QTY  )0, //任务内部消息队列能够接收的最大消息数目,为0时禁止接收消息
                 (OS_TICK   )0, //当使能时间片轮转时的时间片长度,为0时为默认长度,
                 (void    * )0, //用户补充的存储区
                 (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, //任务选项
                 (OS_ERR  * )&err); //存放该函数错误时的返回值
OS_CRITICAL_EXIT(); //退出临界区  
OSStart(&err); 
 
while(1);
}

//开始任务任务函数
void start_task(void *p_arg)
{
OS_ERR err;
CPU_SR_ALLOC();
p_arg = p_arg;

CPU_Init();
#if OS_CFG_STAT_TASK_EN > 0u
   OSStatTaskCPUUsageInit(&err);   //统计任务                
#endif

#ifdef CPU_CFG_INT_DIS_MEAS_EN //如果使能了测量中断关闭时间
    CPU_IntDisMeasMaxCurReset();
#endif

#if OS_CFG_SCHED_ROUND_ROBIN_EN   //当使用时间片轮转的时候
 //使能时间片轮转调度功能,时间片长度为1个系统时钟节拍,既1*5=5ms
OSSchedRoundRobinCfg(DEF_ENABLED,1,&err);  
#endif

OS_CRITICAL_ENTER(); //进入临界区

//创建一个互斥信号量
OSMutexCreate((OS_MUTEX* )&TEST_MUTEX,
  (CPU_CHAR* )"TEST_MUTEX",
                  (OS_ERR* )&err);

//创建TASK2任务
OSTaskCreate((OS_TCB  * )&Task2_TaskTCB,
 (CPU_CHAR * )"task2 task", 
                 (OS_TASK_PTR )task2_task, 
                 (void * )0,
                 (OS_PRIO   )TASK2_TASK_PRIO,     
                 (CPU_STK   * )&TASK2_TASK_STK[0],
                 (CPU_STK_SIZE)TASK2_STK_SIZE/10,
                 (CPU_STK_SIZE)TASK2_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  * )&err);
 
//创建TASK1任务
OSTaskCreate((OS_TCB  * )&Task1_TaskTCB,
 (CPU_CHAR * )"Task1 task", 
                 (OS_TASK_PTR )task1_task, 
                 (void * )0,
                 (OS_PRIO   )TASK1_TASK_PRIO,     
                 (CPU_STK   * )&TASK1_TASK_STK[0],
                 (CPU_STK_SIZE)TASK1_STK_SIZE/10,
                 (CPU_STK_SIZE)TASK1_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  * )&err);
 
 
OS_CRITICAL_EXIT(); //退出临界区
OSTaskDel((OS_TCB*)0,&err); //删除start_task任务自身,   NULL删除自身
}

//task1任务函数
void task1_task(void *p_arg)
{
u16 i;
u8 task1_num=0;
OS_ERR err;
CPU_SR_ALLOC();
p_arg = p_arg;

POINT_COLOR = BLACK;
OS_CRITICAL_ENTER();
LCD_DrawRectangle(5,110,115,314);  //画一个矩形
LCD_DrawLine(5,130,115,130); //画线
POINT_COLOR = BLUE;
LCD_ShowString(6,111,110,16,16,"Task1 Run:000");
OS_CRITICAL_EXIT();

while(1)
{
task1_num++; //任务执1行次数加1 注意task1_num1加到255的时候会清零!!
LED0= ~LED0;
printf("任务1已经执行:%d次\r\n",task1_num);

// if(task1_num==5) 
// {
// OSTaskDel((OS_TCB*)&Task2_TaskTCB,&err); //任务1执行5此后删除掉任务2
// printf("任务1删除了任务2!\r\n");
// }

for(i=0;i<100;i++)
{
OSMutexPend (&TEST_MUTEX,0,OS_OPT_PEND_BLOCKING,0,&err); //请求互斥信号量
LCD_Fill(6,131,114,313,lcd_discolor[task1_num%14]);  //填充区域
LCD_ShowxNum(86,111,task1_num,3,16,0x80); //显示任务执行次数
OSMutexPost(&TEST_MUTEX,OS_OPT_POST_NONE,&err); //释放互斥信号量
OSTimeDlyHMSM(0,0,0,10,OS_OPT_TIME_HMSM_STRICT,&err);  //延时1s
}
}
}

//task2任务函数
void task2_task(void *p_arg)
{
u16 i;
u8 task2_num=0;
OS_ERR err;
CPU_SR_ALLOC();
p_arg = p_arg;

POINT_COLOR = BLACK;
OS_CRITICAL_ENTER();
LCD_DrawRectangle(125,110,234,314); //画一个矩形
LCD_DrawLine(125,130,234,130); //画线
POINT_COLOR = BLUE;
LCD_ShowString(126,111,110,16,16,"Task2 Run:000");
OS_CRITICAL_EXIT();
while(1)
{
task2_num++; //任务2执行次数加1 注意task1_num2加到255的时候会清零!!
LED1=~LED1;
printf("任务2已经执行:%d次\r\n",task2_num);

for(i=0;i<1000;i++)
{
OSMutexPend (&TEST_MUTEX,0,OS_OPT_PEND_BLOCKING,0,&err);//请求互斥信号量
LCD_ShowxNum(206,111,task2_num,3,16,0x80);  //显示任务执行次数
LCD_Fill(126,131,233,313,lcd_discolor[13-task2_num%14]); //填充区域
OSMutexPost(&TEST_MUTEX,OS_OPT_POST_NONE,&err); //释放互斥信号量
OSTimeDlyHMSM(0,0,0,1,OS_OPT_TIME_HMSM_STRICT,&err); 
}
}
}
回复

使用道具 举报

35

主题

227

帖子

3

精华

高级会员

Rank: 4

积分
956
金钱
956
注册时间
2014-3-5
在线时间
35 小时
发表于 2015-7-22 21:55:07 | 显示全部楼层
得定义互斥信号量吧,还没深入研究。。。
把看到的有意义的例子进行扩充,并将其切实的运用到自己的设计中。 应用确实不容易,水平是在不断的实践中完善和发展的。
回复

使用道具 举报

32

主题

183

帖子

0

精华

高级会员

Rank: 4

积分
617
金钱
617
注册时间
2013-1-16
在线时间
131 小时
发表于 2017-11-1 10:22:20 | 显示全部楼层
比如我有个两个任务要往nand flash里面不同page写数据,这时候该怎么办了
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2024-11-27 01:21

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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