ucOSII学习笔记标志事件组信号量邮箱互斥.docx
- 文档编号:8636323
- 上传时间:2023-02-01
- 格式:DOCX
- 页数:30
- 大小:34.80KB
ucOSII学习笔记标志事件组信号量邮箱互斥.docx
《ucOSII学习笔记标志事件组信号量邮箱互斥.docx》由会员分享,可在线阅读,更多相关《ucOSII学习笔记标志事件组信号量邮箱互斥.docx(30页珍藏版)》请在冰豆网上搜索。
ucOSII学习笔记标志事件组信号量邮箱互斥
目前因项目开发要用到ucOSII,在网上查找到了一些资料,为方便其他同仁,把我个人认为写得很好的文档摘抄到一个文件中,并上传到XX空间,希望对初学都有所帮助。
UCOS事件标志组管理笔记Ⅰ
说明:
本文摘自网上,来源已忘记,望原作者见谅。
当某个任务需要与多个任务同步时,须要使用事件标志组。
1、弄清楚OS_FLAG_GRP、OS_FLAG_NODE和OS_TCB之间的关系。
当一个任务开始等待某些事件标志位时,就回建立一个事件标志节点OS_FLAG_NODE数据结构,并且将任务所要等待的事件标志位写入OS_FLAG_NODE的分量.OSFlagNodeFlags。
然后将该数据结构分量.OSFlagNodeFLagGrp指向事件标志组OS_FLAG_GRP,将.OSFlagNodeTCB指向该任务的控制块OS_TCB,建立起任务与事件标志组之间的联系,说明该任务是等待该事件标志组中某些事件标志位的任务。
当有多个任务都需要等待某个事件标志组中某些事件标志位时,这些任务分别建立自己的事件标志节点。
并且将这些事件标志节点通过分量.OSFlagNodeNext和.OSFlagNodePrev连接成链。
⒉、任务可以等待事件标志组中某些位置位1,也可以等待事件标志组中某些位清0,而置1(或清0)又可以分为所有事件都发生的“与”型和任何一个事件发生的“或”型。
这样便有了4种不同的类型存放在.OSFlagNodeWaitType(OS_FLAG_NODE)中。
3、事件标志组和信号量我觉得是有不同的。
信号量建立以后,假设初始值为N,前N个任务调用OSSemPend()函数都会得到信号量。
之后如果第N+1个任务调用OSSemPend()函数申请信号量,该任务将会被置为等待事件发生的状态(睡眠态)。
只到前N个任务中有任务运行完了所要运行的程序,调用OSSenmPost()函数,释放了所占用了信号量,第N+1个任务。
(这里假设该任务是所有等待信号量任务中优先级最高的任务)才会获得信号量,被从睡眠态转入就绪态。
而事件标志组是事件标志组建立之后,某个任务需要事件标志组中某些事件标志位(置位或者清0)才能继续运行,于是任务调用OSFlagPend()函数,而此时若这些标志位满足要求,任务返回,继续执行。
否则,任务将被挂起。
而当有另外一个任务调用OSFlagPost()函数将前一个任务所需要的标志位(置位或清0)使之满足要求,前一个被挂起的任务将被置为就绪态。
因此几个任务可以同时得到所需要的事件标志进入就绪态。
注意:
只要任务所需要的标志位满足要求,任务便进入就绪态。
与信号量不同,信号量中的任务需要是在等待该信号量中优先级最高的任务才能得到信号量进入就绪态。
事件标志组可以一个任务与多个任务同步,而信号量只能是一个任务与另一个任务同步
以下所有文档摘自一位网友博客上的,写的很好,转一下:
ucosii学习
(2)事件标志组
2010-08-2320:
54
FLAG-事件标志组管理,在UCOSII里我个人觉相对比较复杂,首先我们要有个大致的概念,就是FLAG事件组能用来干什么。
以下只摘自一位网友博客上的,写的很好,转一下:
(一)描述:
对于flag--"事件组"的使用,可以用一个简单的例子做说明:
比如,我现在用迅雷下载一部10集的连续剧,我打算10集全部下载完成之后,才开始正式看,现在3~10集因为种子原因,先早下完了,现在第1集下到了82%,第2集下到了97%,因为我的计划是10集全部下完才开始看,而第1集和第2集由于网络,种子等等各种原因,迟迟不能下载完成,进而导致我的计划被悬停,不能进行,已下载的8集,也因为前2集没能下完,而白白等待---这就等同于flag事件组,1~10集,每一集都是一个事件,因为我内定,10个事件全部完成之后,才进入下一事件--"观看"所以及早完成自己事件的第3~10集,将主动把自己通过flag事件组函数OSFlagPost()登记到事件组上,他们不关心,其他友邻事件完成否,只专注自己的事件是否完成,自己的事件一旦完成就登记到事件组上,最后3~10集,都把自己登记上去了,只剩下第1集和第2集,一旦某天的某个时刻,第2集下完了,那么第2集也把自己登记到事件组上,这样整个事件距离完成还剩下一个事件,就是第1集是否下载完成,只要第1集下载完成,那么我内定的"观看"计划开始启动,过了3分钟,由于网速提高,竟以300k的速度开始下载第1集,1分钟之后,第1集也下载完成了,第1集立即调用OSFlagPost事件组函数,将自己登记到事件组上,ok,OSFlagPost()检测到所有事件已经完成,OSFlagPost()将是"我"自动进入下一事件---"观看"还有一点就是关于flag事件组和Sem,Mbox,Queue的区别之处,flag事件组不使用事件控制矩阵来管理被阻塞在事件上的task进程,flag事件组使用pgrp的双向链表来挂接起所有task,在OSFlagPost()中将遍历这个链表,查找符合当前flag事件的task,将该task从双向链表中摘下然后放入就绪控制矩阵中,之所以这样,是因为flag事件组不像Sem,Mbox,Queue那样具有二值性,即Sem,Mbox,Queue,要么有,要么没有,flag事件组,还要进一步判断,有的话,是什么程度的有。
通过以上介绍,对于FLAG事件组有了大致的了解,但要具体了解其实现过程,最好还是去看看其原代码,原代码就不在这贴出来了。
UCOSII使用等待事件标志组的任务列表是一个双向链表,使用了3个数据结构:
OS-FLAG-GRP,任务控制块TCB,OS-FLAG-NODE。
特别是对OS-FLAG-NODE我觉得要注意一下,当一个任务开始等待某些事件标志时,就建立一个OS-FLAG-NODE数据结构。
当这些等待事件标志发生后,这个数据被删除。
具体分析看邵贝贝老师的书,写的比较详细。
对于原代码自己在有些细节上还是有些没有弄清楚,但基本用用还是可以的,下面就来举几个自己实现过的例子吧。
(二)举例。
以下举的例子,是自己从网上找来的,再经过一定的修改,在STM32上跑的。
1).简单的OSFLAGPEND()与OSFLAGPOST()函数的应用
显示用,LCD1602和两个LED灯(条件有限啊)
TASK1():
建一个OSFlagPend()若等待事件标志没有发生该函数挂起该任务若事件标志发生,则LCD显示一个值,LED灯每隔一秒闪一次。
TASK2():
OSFlagPost()向任务一发送一个信号量
TASK3():
OSFlagPost()向任务一发送一个信号量,具体看代码
staticvoidTask1(void*pdata)
{
INT8Uerror;
INT8Ui=0;
pdata=pdata;
while
(1)
{//若等待事件标志没有发生该函数挂起该任务
OSFlagPend(
Sem_F,//请求信号量集
(OS_FLAGS)3,//请求第0位和第1位信号
//且都置为1时为有效否则任务挂在这里
OS_FLAG_WAIT_SET_ALL,
0,//无限等待直到收到为止
&error);
//OSFLAGPEND收到有效信号后在LCD显示字符串
//闪两个LED可以跟据自己代码而?
write_com(0x80+10);
while(table1[i]!
='\0')
{
write_dat(table1[i]);
i++;
}
GPIO_ResetBits(GPIOD,GPIO_Pin_15);
GPIO_ResetBits(GPIOD,GPIO_Pin_13);
//任务挂起1秒否则优先级低的任务就没机会执行了
OSTimeDlyHMSM(0,0,1,0);
GPIO_SetBits(GPIOD,GPIO_Pin_15);
GPIO_SetBits(GPIOD,GPIO_Pin_13);
OSTimeDlyHMSM(0,0,1,0);//让两个LED每秒闪一次
}
}
staticvoidTask2(void*pdata)
{
INT8Uerror;
pdata=pdata;
while
(1)
{
OSFlagPost(Sem_F,//发送信号量集
(OS_FLAGS)2,//给第1位发信号
OS_FLAG_SET,//信号量置1
&error
);
OSTimeDlyHMSM(0,0,1,0);//等待1秒
}
}
staticvoidTask3(void*pdata)
{
INT8Uerror;
pdata=pdata;
while
(1)
{
//在执行此函数时发生任务切换去执行TASK1在OSFLAGPOST中发生任务切换
OSFlagPost(//发送信号量集
Sem_F,
(OS_FLAGS)1,//给第0位发信号
OS_FLAG_SET,//信号量置1
&error
);
OSTimeDlyHMSM(0,0,1,0);//等待1秒
}
}
voidmain(void)
{
#if(OS_TASK_NAME_SIZE>14)&&(OS_TASK_STAT_EN>0)
INT8Uerr;
#endif
//目标板初始化,
Target_Init();
lcd_init();
OSInit();
//设置空闲任务名称
#ifOS_TASK_NAME_SIZE>14
OSTaskNameSet(OS_TASK_IDLE_PRIO,"uC/OS-IIIdle",&err);
#endif
//设置统计任务名称
#if(OS_TASK_NAME_SIZE>14)&&(OS_TASK_STAT_EN>0)
OSTaskNameSet(OS_TASK_STAT_PRIO,"uC/OS-IIStat",&err);
#endif
Sem_F=OSFlagCreate(0,&error);
//用任务建立任务
OSTaskCreateExt(APP_TaskStart,//void(*task)(void*pd)任务首地址
(void*)0,//void*pdata数据指针
//OS_STK*ptos指向任务堆栈栈顶的指针
&APP_TaskStartStk[APP_TASK_START_STK_SIZE-1],
//INT8Uprio任务优先级
(INT8U)APP_TASK_START_PRIO,
//INT16Uid任务的ID号
(INT16U)APP_TASK_START_ID,
//OS_STK*pbos指向任务堆栈栈底的指针
&APP_TaskStartStk[0],
//INT32Ustk_size堆栈容量
(INT32U)APP_TASK_START_STK_SIZE,
(void*)0,//void*pnext数据指针
//INT16Uopt设定OSTaskCreateExt的选项
OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR
);
OSStart();
}
上述例子中,TASK1()OSFLGAPEND()需要第0,1位都置位时才有效,任务刚进来时不满足即被挂起。
等待着OSFLGAPOST()把相应位置1。
TASK2,TASK3分别把第0,1位置位。
即等到执行完TASK3时,TASK1()有效。
2.)若TASK1()如下
staticvoidTask1(void*pdata)
{
INT8Uerror;
INT8Ui=0;
pdata=pdata;
while
(1)
{
//若等待事件标志没有发生该函数并不挂起该任务
OSFlagAccept(//请求信号量集
Sem_F,
(OS_FLAGS)3, //请求第0位和第1位信号
//第0位和第1位信号都为1为有效
OS_FLAG_WAIT_SET_ALL,
&error
);
//OSFLAGPEND收到有效信号后在LCD显示字符串
//闪两个LED可以跟据己代码而定
write_com(0x80+10);
while(table1[i]!
='\0')
{
write_dat(table1[i]);
i++;
}
GPIO_ResetBits(GPIOD,GPIO_Pin_15);
GPIO_ResetBits(GPIOD,GPIO_Pin_13);
//任务挂起1秒否则优先级低的任务就没机会执行了
OSTimeDlyHMSM(0,0,1,0);
GPIO_SetBits(GPIOD,GPIO_Pin_15);
GPIO_SetBits(GPIOD,GPIO_Pin_13);
OSTimeDlyHMSM(0,0,1,0); //让两个LED每秒闪一次
}
}
即为无等待获取,当信号量不满足,任务也不挂起,即TASK2(),TASK3()不给OSFLAGCCEPT()发送信号,TASK1()仍然执行,在本例中,LCD,LED显示正常。
3.)我们还可以用OSFLGAQUERY()来查询事件标志组的状态。
跟据状态来执行自己所期望的代码,用起来很方便且很好。
staticvoidTask1(void*pdata)
{
INT8Uerror;
INT8Ui=0,j=0,k=0,Flags;
pdata=pdata;
while
(1)
{
Flags=OSFlagQuery( //查询事件标志组的状态
Sem_F,
&error
);
switch(Flags)
{
case1:
write_com(0x80+10);
while(table1[i]!
='\0')
{
write_dat(table1[i]);
i++;
}
break;
case2:
write_com(0x80+0x40);
while(table2[j]!
='\0')
{
write_dat(table2[j]);
j++;
}
break;
case3:
write_com(0x80+0x40+8);
while(table3[k]!
='\0')
{
write_dat(table3[k]);
k++;
}
break;
}
OSTimeDlyHMSM(0,0,1,0); //等待2秒
}
}
(三)总结,对于FLAG事件组大致就这些吧。
自己也正在学习中,可能有很多地方还不对。
最后再讲一点体会吧。
关键是理解两个函数,OSFLAGPEND(),OSFLAGPOST()。
具体它们是在干什么的:
OSFLAGPEND():
任务等待事件标志组中的事件标志,可以是多个事件标志的不同组合方式。
可以等待任意指定事件标志位置位或清0,也可以是全部指定事件标志位置位或清0。
如果任务等待的事件标志位条件尚不满足,则任务会被挂起,直到指定的事件标志组合发生或指定的等待时间超时。
OSFLAGPOST():
给出设定的事件标志位。
指定的事件标志位可以设定为置位或清除。
若OSFlagPost()设置的事件标志位正好满足某个等待使劲标志组的任务,则OSFlagPost()将该任务设为就绪。
注意:
必须先创建事件标志组,然后使用;这个函数的运行时间决定于等待事件标志组的任务的数目;关闭中断的时间也取决于等待事件标志组的任务的数目。
(四)参考资料:
来自各位网友博客
《嵌入式实时操作系统第2版》
ucosii学习(3)信号量
2010-08-2521:
51
对于UCOSII中信号量的理解相对还是比简单的,但怎么能够灵活的运用还是要多实践的。
信号量为操作系统用于处理临界区问题和实现进程间同步提供了一种有效的机制。
想要具体深入了解最好去看看原代码。
(一)、描述。
以下文字摘自一位网友的。
作者:
yzhu于2006-2-920:
49:
00发布:
以下为个人理解,仅供参考
简单地说:
当信号量=0时,表示信号量代表的资源不可用,操作系统就调用OSSemPend()函数的任务加入该信号量的等待任务列表中;
当信号量>0时,表示信号量代表的资源可用,OSSemPend()函数返回,任务可以使用资源。
一般地,信号量的最大值(nmax)表示资源的最大同时共享数。
nmax=1,表示资源最多只能由一个任务使用,如读写某内存单元时,为保证该单元不被其它任务篡改,就使用nmax=1的(二值)信号量;nmax>1,表示资源可由多个任务使用,如FIFO,一个任务写某单元时,另一个任务可以写其它单元,则可使用nmax>1的(多值)信号量,信号量的大小用来表示FIFO的可用单元数。
减1操作:
当该信号量=0时表示FIFO已满,任务只能等待;当该信号量>0时表示FIFO有空,可以使用,同时要减1表示调用OSSemPend()函数的任务已经使用了一个资源(FIFO单元),可使用资源少了一个。
加1操作:
当某任务调用OSSemPost()从FIFO中取出一个值时,该FIFO单元就空出一个可写单元,也就是资源多了一个,为表示这个变化,信号量要加1,一旦信号量由0->1,则把资源给等待任务列表中优先级最高的任务(通过OSSemPend()函数的返回)。
总之,信号量的值代表共享资源的剩余量,用掉一个减1,空出一个加1。
举个例子:
顾客(任务)到银行办事,银行(OS)现有N名业务员(共享资源)。
1.办事前先要取号(OSSemPend()),号条一般有“前面有xx位顾客”,表示正在等待服务(资源)的顾客(任务)数。
2.另外假设银行有一指示牌(信号量)指示当前空闲的业务员的数量为n(信号量的值)。
3.当n>0时,表示有空闲的业务员,那么顾客可以立即去业务员那办理业务(OSSemPend()立即返回),这样空闲的业务员就少一个,指示牌指示的数量(信号量的值)就要减1,但n只能减到N。
4.当n=0时,表示没有空闲的业务员,那么顾客只能等待(OSSemPend()不返回,切换到其它任务)。
5.当某位业务员为顾客办完手续后,他就空闲下来,这样空闲的业务员就多一个,指示牌指示的数量(信号量的值)就要加1,但n只能加到N。
这时银行就会去查找有没有正在等待的顾客,如果有,就找出其中优先级最高的顾客,让他来办理业务(OSSemPend()返回)。
6.顾客在取号时若设置了等待时间,那么在等待时间过后,银行就会通知顾客时间到(OSSemPend()返回),顾客接着去办其它事。
7.也有的顾客希望:
在取号时,如果有空闲的业务员他就办事,没有的话就走(去办其它事),那么就要用特殊的取号方式(OSSemAccept())。
8.N=1时,表示只有一个业务员,指示牌只能指示0或1两个值,这就是二值信号量。
不知道这个例子能不能说清楚信号量的概念,请大伙完善。
(二)、代码举例。
通过上述文字的描述,我想我们对信号量有了一定的了解,下面的一些代码是自己在自己开发板上跑的,运行结果只是为了分析各任务运行情况,一定有很多不妥之处。
1.)用信号量实现同步。
建立TASK1(),TASK2()。
实现两个任务同步,以LED灯来显示。
staticvoidTask1_LED1(void*pdata) //优先级10
{
INT8Uerror;
pdata=pdata;
while
(1)
{
OSSemPend(sem,0,&error);//任务作1刚进来由SEM=0即任务被挂起转而执行任务2
GPIO_SetBits(GPIOD,GPIO_Pin_11);
GPIO_ResetBits(GPIOD,GPIO_Pin_10);
//由于任务2释放信号量后执行到此外任务1又要申请信号量
//即又被挂起等待信号量再次释放
OSSemPend(sem,0,&error); GPIO_SetBits(GPIOD,GPIO_Pin_10);
GPIO_ResetBits(GPIOD,GPIO_Pin_11);
}
}
staticvoidTask2_LED2(void*pdata) //优先级11
{
pdata=pdata;
while
(1)
{
GPIO_SetBits(GPIOD,GPIO_Pin_9);
GPIO_ResetBits(GPIOD,GPIO_Pin_8);
//任务执行到此处释放信号量SEM因为TASK1在等待该信号量马上切换到任务1
OSSemPost(sem);
OSTimeDlyHMSM(0,0,1,0); //挂起1秒
GPIO
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- ucOSII 学习 笔记 标志 事件 信号量 邮箱
![提示](https://static.bdocx.com/images/bang_tan.gif)