UCOSII信号量

8 篇文章 0 订阅
5 篇文章 0 订阅

µC/OSII是通过优先级先后顺序进行就绪任务调度的系统,这样导致任务多的时候不好进行任务调度,容易出现乱序。这个时候使用信号量能做到任务之间的同步。

前情提要:信号量的控制在os_cfg.h中的宏进行更改。

OS_SEM_EN 此为信号量使能宏定义,使用信号量功能需要置1

目录

信号量管理函数

OSSemAccept()

OSSemCreate ()

OSSemDel ()

OSSemPend()

OSSemPendAbort()

OSSemPost()

OSSemQuery()

OSSemSet()

示例代码

代码验证结果


信号量管理函数

OSSemAccept()

作用:无需等待查看是否有信号量

原型:INT16U OSSemAccept(OS_EVENT *pevent);

注意:该函数不会导致任务被挂起(挂起:任务在列表中,但是不执行),中断也可以调用此函数查询信号量

参数:OS_EVENT *pevent:信号量的控制块指针(就是创建信号量函数的返回值)

返回值:INT16U 返回信号量的值,大于0任务就绪。此函数会消耗一个信号量。

OSSemCreate ()

作用:创建信号量

原型:OS_EVENT *OSSemCreate(INT16U value);

注意:此函数不允许在中断中调用!必须在使用信号量前创建。

参数:INT16U value:初始信号量值(每经过一个等待信号量函数OSSemPend(),此值会递减,当为0时,等待信号量函数的任务不会往下继续执行)

返回值:OS_EVENT 返回信号量的控制块指针,其他函数需要关联此信号量都需要控制块。

OSSemDel ()

作用:删除信号量

原型:OS_EVENT *OSSemDel(OS_EVENT *pevent, INT8U opt, INT8U *perr);

注意:必须先创建信号量。

参数:OS_EVENT *pevent:信号量控制块指针

           INT8U opt:OS_DEL_ALWAYS直接删除、OS_DEL_NO_PEND不存在任务挂起时删除

           INT8U *perr:错误码 自己查 ucos_ii.h OS_ERR_XXX表示错误码:OS_ERR_NONE

返回值:如果信号量被成功删除,则返回空指针;否则需要根据错误代码进行检查。

OSSemPend()

作用:申请一个信号量

原型:void OSSemPend (OS_EVENT *pevent, INT32U timeout, INT8U *perr);

注意:此函数会挂起任务等待信号量。

参数:OS_EVENT *pevent:信号量控制块指针

           INT32U timeout:写入0时表示一直等待,写入正数值表示周期性递减到0时往下执行任务

           INT8U *perr:错误码 自己查 ucos_ii.h OS_ERR_XXX表示错误码:OS_ERR_NONE

返回值:

OSSemPendAbort()

作用:使正在等待该信号量的任务取消挂起。不再等待。

原型:void OSSemPend (OS_EVENT *pevent, INT32U timeout, INT8U *perr);

注意:此函数执行一次,等待任务就取消挂起一次

参数:OS_EVENT *pevent:信号量控制块指针

           INT32U timeout:写入0时表示一直等待,写入正数值表示周期性递减到0时往下执行任务

           INT8U *perr:错误码 自己查 ucos_ii.h OS_ERR_XXX表示错误码:OS_ERR_NONE

返回值:

OSSemPost()

作用:发送信号量,每执行一次信号量增加1个数

原型:INT8U OSSemPost(OS_EVENT *pevent);

注意: 信号量会优先给正在等待就绪优先级高的任务,如果高优先级任务执行,信号量就会被消耗。所以一定要注意调度问题。比如两个任务都等待信号量且信号量只有一个,高优先级任务先执行,第二个任务没有信号量就没办法执行了。

参数:OS_EVENT *pevent:信号量控制块指针

           INT32U timeout:写入0时表示一直等待,写入正数值表示周期性递减到0时往下执行任务

           INT8U *perr:错误码 自己查 ucos_ii.h OS_ERR_XXX表示错误码:OS_ERR_NONE

返回值:

OSSemQuery()

作用:获取一个信号量的相关信息。

原型:INT8U OSSemQuery(OS_EVENT *pevent, OS_SEM_DATA *p_sem_data);

注意: 信号量会优先给正在等待就绪优先级高的任务,如果高优先级任务执行,信号量就会被消耗。所以一定要注意调度问题。比如两个任务都等待信号量且信号量只有一个,高优先级任务先执行,第二个任务没有信号量就没办法执行了。

参数:OS_EVENT *pevent:信号量控制块指针

           OS_SEM_DATA *p_sem_data:存放获取到信息的结构体

返回值:错误码 自己查 ucos_ii.h OS_ERR_XXX表示错误码:OS_ERR_NONE

OSSemSet()

作用:改变当前信号量的计数值。

原型:void OSSemSet(OS_EVENT *pevent, INT16U cnt, INT8U *perr);

注意: 信号量被用于表示某事件发生了多少次的情况下会使用。这个函数只能修改当信号量>0 的情况,也就是没有任务等待信号量的情况。

参数:OS_EVENT *pevent:信号量控制块指针

           INT16U cnt:期望的数值。 类似刷新值

           INT8U *perr:错误码 自己查 ucos_ii.h OS_ERR_XXX表示错误码:OS_ERR_NONE

返回值:无

示例代码

例如:创建3个任务,当任务2执行后3次后,给任务1发送一个信号量使每3次执行任务2时任务1都能执行,当任务3执行10次将挂起任务2。导致任务2任务1都不执行。其余的函数各位自己去验证

#include "stm32f4xx.h"
#include "usart1.h" 
#include "delay.h"
#include "includes.h"

/*初始任务*/
#define Start_TASK_PRO    10             /*任务优先级*/
#define Start_STACK_SIZE  64             /*任务栈大小*/
OS_STK Start_STask[Start_STACK_SIZE];    //设置一个数组用于存放缓冲数据(入栈时的数据)
void Start_Task(void *parameter);            //任务声明
 
 
/*任务一*/
#define Mission_One_PRO    12            /*任务优先级*/
#define Mission_One_SIZE  64             /*任务栈大小*/
OS_STK Mission_One[Mission_One_SIZE];    //设置一个数组用于存放缓冲数据(入栈时的数据)
void Mission_One_Func(void *parameter);  //任务声明
 
/*任务二*/
#define Mission_Two_PRO    14            /*任务优先级*/
#define Mission_Two_SIZE  64             /*任务栈大小*/
OS_STK Mission_Two[Mission_Two_SIZE];    //设置一个数组用于存放缓冲数据(入栈时的数据)
void Mission_Two_Func(void *parameter);  //任务声明
 
/*任务三*/
#define Mission_Three_PRO    16          /*任务优先级*/
#define Mission_Three_SIZE  64           /*任务栈大小*/
OS_STK Mission_Three[Mission_Three_SIZE];//设置一个数组用于存放缓冲数据(入栈时的数据)
void Mission_Three_Func(void *parameter);//任务声明
 
OS_EVENT *DispSem;//信号量控制块指针

int main()//一个工程只能有一个main函数
{
    //优先级分组,代码中只执行一次   
    INT8U res;//返回标志
    NVIC_SetPriorityGrouping(5);//优先级分组,组2 101
    Systick_Inti(168);  
    Usart1_Init(115200); 
    
    OSInit(); // 初始化 uC/OS-II  必须要有
    res=OSTaskCreate(Start_Task,(void *)10,&Start_STask[Start_STACK_SIZE-1],Start_TASK_PRO);//创建初始任务
    if(res==OS_ERR_NONE)
    printf("Start_Task\r\n");  //判断任务创建成功 
    OSStart(); //启动多任务内核 调度 
    //后面的代码都不会执行
    while(1);
}
 
//初始任务,任务中可以创建任务,并且初始任务只执行一次
void Start_Task(void *parameter)
{
    INT8U res;//返回标志
    parameter = parameter;//防止编译器报警告
    printf("Perform the initial task\r\n");  
    OSStatInit();
    DispSem=OSSemCreate(0);//创建信号量 ,初始0个信号量,任务直接等待状态
//  DispSem=OSSemCreate(5);//创建信号量 ,初始有5个信号量,被任务执行五次后直接进入等待状态
    res=OSTaskCreate(Mission_One_Func,0,&Mission_One[Mission_One_SIZE-1],Mission_One_PRO);//创建任务
    if(res==OS_ERR_NONE)
    printf("Mission_One_Func\r\n");  //任务创建成功 
    
    res=OSTaskCreate(Mission_Two_Func,0,&Mission_Two[Mission_Two_SIZE-1],Mission_Two_PRO);//创建任务
    if(res==OS_ERR_NONE)
    printf("Mission_Two_Func\r\n");  //任务创建成功 
    
    res=OSTaskCreate(Mission_Three_Func,0,&Mission_Three[Mission_Three_SIZE-1],Mission_Three_PRO);//创建任务
    if(res==OS_ERR_NONE)
    printf("Mission_Three_Func\r\n");  //任务创建成功 
 
    OSTaskDel(OS_PRIO_SELF);//自杀 删除自己
}
 
//任务1
void Mission_One_Func(void *parameter)
{
    INT8U err;//错误码
    parameter = parameter;//防止编译器报警告
    u32 flag=0;
    while(1)
    {
        OSSemPend(DispSem, 0, &err);//等待信号量,第二参数写入0表示一直等待
        printf("Mission_One_Func execute\r\n");   
        OSTimeDlyHMSM(0,0,0,500); //500ms  释放CPU
    }
}
void Mission_Two_Func(void *parameter)
{
    INT8U err;//错误码
    parameter = parameter;//防止编译器报警告
    u32 Sem_flag=0;
    while(1)
    {
        if(++Sem_flag==3)//每执行3次任务2发送一次信号量
        {
          Sem_flag=0;
          OSSemPost(DispSem);//发送一个信号量,错误码返回值不成功就自己去添加打印查看     
        }
        printf("Mission_Two_Func execute\r\n");   
        OSTimeDlyHMSM(0,0,0,500); //500ms  释放CPU
    }
}
void Mission_Three_Func(void *parameter)
{
    parameter = parameter;//防止编译器报警告
    u32 Sem_flag=0;
    while(1)
    {   
        if(++Sem_flag==10)
        {
          Sem_flag=0;
          OSTaskSuspend(Mission_Two_PRO);//执行10次后挂起任务2,任务1获取不到信号量,只执行任务3     
        }
        printf("Mission_Three_Func execute\r\n");   
        OSTimeDlyHMSM(0,0,0,500); //500ms  释放CPU             
    }
}
//此代码没意义就是为了更简单验证,不加入按键获取LED等功能

代码验证结果

Mission_One_Func       //创建任务1
Mission_Two_Func //创建任务2
Mission_Three_Func    //创建任务3
Mission_Two_Func execute
Mission_Three_Func execute
Mission_Two_Func execute
Mission_Three_Func execute
Mission_One_Func execute  //第一次获得信号量,任务1优先级比任务2高,当任务2第三次进入发送信号量时,立马被任务1抢占CPU执行完后再回到任务2
Mission_Two_Func execute  
Mission_Three_Func execute
Mission_Two_Func execute
Mission_Three_Func execute
Mission_Two_Func execute
Mission_Three_Func execute
Mission_One_Func execute//第二次获得信号量

Mission_Two_Func execute
Mission_Three_Func execute
Mission_Two_Func execute
Mission_Three_Func execute
Mission_Two_Func execute
Mission_Three_Func execute
Mission_One_Func execute//第三次获得信号量
Mission_Two_Func execute
Mission_Three_Func execute
Mission_Two_Func execute
Mission_Three_Func execute//任务2被挂起,导致任务1获取不到信号量不执行
Mission_Three_Func execute
Mission_Three_Func execute

,,,,,

总结:信号量主要用于任务同步,我通过任务3可以一次调用两个发送信号量函数,分别给任务1任务2等待信号量函数,那么只要任务3想要获取数据便发送信号量,可以通过任务1与任务2获得信号量取消等待进行执行获取数据,实现3个任务联动。

  • 21
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小刘刘的奇妙冒险

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值