zoukankan      html  css  js  c++  java
  • UCOSII使用之信号量,邮箱

    信号量

    在ucos-II中,为了实现任务之间的同步,用到的同步机制有:信号量,邮箱和消息队列。其中这里我主要说下对信号量的使用经验。信号量在创建时,      调用OSSemCreate(INT16U cnt)函数。cnt为信号量的初始值。对cnt赋予不同的值,所起到的作用不同。如果Semp = OSSemCreate(0), 该信号量表示等待一个事件或者多个事件的发生。

          如果我们想对一个公共资源进行互斥访问,例如:如果我们想让两个任务Task1和Task2都可以调用Fun()函数,但不能同时调用,最好定义Semp = OSSemCreate(1),同理在各自的任务中都需要调用OSSemPend(Semp,0,&err)请求此信号量,如果可用,则调用Fun(),然后再调用OSSemPost(Semp)释放该信号量。这里就实现了一个资源的互斥访问。(注:初始化OSSemCreate(1),那么一个任务中有OSSemPend,那么可以执行,执行之后cnt==0,其他任务的OSSemPend无法获得sem,只能等待,除非任务一有OSSemPost,使其cnt++,这样其他任务的Pend可以执行。)同理,如果一个任务要等待n个事件发生后才能执行,则应定义为Semp = OSSemCreate(n)。然后在这n个任务分别运行时调用OSSemPost(Semp),直到这n个事件均发生后,这个任务才能运行。

    OSSemCreate(cnt)赋初始值cntOSSemPend一次,cnt-- 一次,OSSemPost一次,cnt++一次。

    //1、OSSemCreate (0);
    //......
    //OS_EVENT *Fun_Semp;
    //......
    
    Fun_Semp = OSSemCreate (0);
    //......
    
    void  MyTask (void *pdata)
    {
    
    .....
        for (;;) 
        {                                           
            OSSemPend(Fun_Semp,0,&err); //请求信号量
       PC_DispStr(0,++y,  s1,  DISP_BGND_BLACK+DISP_FGND_WHITE );
            OSTimeDlyHMSM(0, 0, 1, 0);    //等待1秒
        }
    }
    
    ......
    
    void  YouTask (void *pdata)
    {
    
    ......
        for (;;) 
        {           
      PC_DispStr(0,++y,  s2,  DISP_BGND_BLACK+DISP_FGND_WHITE );
      if(YouTaskRun==5)
           OSSemPost(Fun_Semp);  //发送信号量
      YouTaskRun++;            
            OSTimeDlyHMSM(0, 0, 2, 0);    //等待2秒
        }
    }

    在上例中,MyTask 一直在等待信号量,在信号量没有到来之前无法执行。只有在YouTask 运行了5次,YouTaskRun==5之后,OSSemPost(Fun_Semp);  //发送信号量,MyTask 才得以执行。如果按上例所示,MyTask 只能执行一次,因为YouTask 以后再也不可能使得YouTaskRun==5了。MyTask也就因为无法得到信号量而不能运行。

    //2、OSSemCreate (1);
    //.....
    OS_EVENT *Fun_Semp;
    //.....
    Fun_Semp = OSSemCreate (1);
    //.....
    void  MyTask (void *pdata)
    {
    
    //..... 
        for (;;) 
        {                                           
            OSSemPend(Fun_Semp,0,&err); //请求信号量
       PC_DispStr(0,++y,  s1,  DISP_BGND_BLACK+DISP_FGND_WHITE );
       OSSemPost(Fun_Semp);  //发送信号量
            OSTimeDlyHMSM(0, 0, 1, 0);    //等待1秒
        }
    }
    
    void  YouTask (void *pdata)
    {
    
        for (;;) 
        {                                           
            OSSemPend(Fun_Semp,0,&err); //请求信号量
       PC_DispStr(0,++y,  s2,  DISP_BGND_BLACK+DISP_FGND_WHITE );
    
       OSSemPost(Fun_Semp);  //发送信号量            
            OSTimeDlyHMSM(0, 0, 2, 0);    //等待2秒
        }
    }

    在上例中,MyTask、YouTask 都在 等待信号量,由于MyTask优先级高,首先得到信号量开始执行。此时YouTask 还在等待信号量。MyTask 执行完毕,OSSemPost(Fun_Semp);  //发送信号量。YouTask 得到信号量运行后发送信号量,如此反复

     

    邮箱

     

    /******************************************************************
    
     Name:            Lambda
     Date:            2013.03.23
     Desciption:        创建两个任务,任务1不断循环发送字符A到字符Z,通过
                     邮箱的方式传递数据给任务2,任务2将从任务1收到的数据
                     通过串口打印在超级终端里。
                                             
    *******************************************************************/ 
    
    #include "config.h"
    
    #define     TASK_STK_SIZE    512                        //定义每个堆栈长度为512
    
    OS_STK        TaskStartStk[TASK_STK_SIZE];            //创建起始任务的堆栈
    OS_STK        Task1Stk[TASK_STK_SIZE];            //创建功能任务1的堆栈
    OS_STK        Task2Stk[TASK_STK_SIZE];            //创建功能任务2的堆栈
    OS_EVENT    *TxMbox;                            //定义一个邮箱,用来传递发送消息
    OS_EVENT     *AckMbox;                            //定义一个邮箱,用来传递应答消息
    
    
    void TaskStart(void *pdata);
    static void TaskStartCreateTasks(void);
    void Task1(void *pdata);
    void Task2(void *pdata);
    
    
    /**********************************************************
                                            Main函数
    **********************************************************/
    int Main(void)
    {
        TargetInit();                 //目标板初始化
        OSInit();                       //uC/OS-II初始化
        OSTimeSet(0);              //设置系统时基,建议予以保留
        OSTaskCreate(TaskStart, (void *)0, &TaskStartStk[TASK_STK_SIZE - 1], 7);    //创建起始任务TaskStart  
        OSStart();
    
        return 0;
    }
    
    
    /******************************************************************
                             起始任务函数TaskStart
    *******************************************************************/ 
    
    void TaskStart(void *pdata)
    {
    
        pdata = pdata;                            //防止编译器报警
        
        TxMbox = OSMboxCreate( (void *)0 );        //创建一个邮箱,用来传递发送消息
        AckMbox = OSMboxCreate( (void *)0 );    //创建一个邮箱,用来传递应答消息
        
        TaskStartCreateTasks();                    //调用该函数来创建更多的功能任务
    
        while(1){                                //所有的任务都应该是一个无限循环的过程
            OSTimeDlyHMSM(0,0,1,0);            //将该任务挂起1秒,uCOS-II开始调度,让下一个就绪的最高优先级的任务运行
        }
    
    }
    
    
    /******************************************************************
                     创建功能任务函数TaskStartCreateTasks
    *******************************************************************/
    
    static void TaskStartCreateTasks(void)
    {
        OSTaskCreate(Task1, (void *)0, &Task1Stk[TASK_STK_SIZE - 1], 8);            //创建功能任务Task1,优先级为8,不传递参数
        OSTaskCreate(Task2, (void *)0, &Task2Stk[TASK_STK_SIZE - 1], 9);            //创建功能任务Task2,优先级为9,不传递参数
    }
    
    
    
    /******************************************************************
                             功能任务函数Task1
    *******************************************************************/
    
    void Task1(void *pdata)
    {
        char    TxMsg;
        INT8U err;
        
        pdata = pdata;                                    //防止编译器报警
        
        TxMsg = 'A';    
        while(1)
        {
            OSMboxPost(TxMbox, (void *)&TxMsg);        //把消息A的指针通过邮箱TxMbox发送出去
            OSMboxPend(AckMbox, 0, &err);                //一直等待邮箱AckMbox收到应答信号,只有从任务2收到应答信号后才往下执行
            
            TxMsg++;                                //循环发送字符A到字符Z
            if(TxMsg > 'Z'){
                TxMsg = 'A';
                
            //OSTimeDlyHMSM(0,0,1,0);                    //去掉该函数才能正常打印,但打印速度会非常快; 添加后反而会挂死任务只能打印字符A,就不动了??
                                                    //此处的问题还请有经验的朋友指导一下啊。
                                                    
            }
        }
    }
    
    
    /******************************************************************
                             功能任务函数Task2
    *******************************************************************/
    
    void Task2(void *pdata)
    {
        char    *RxMsg;
        INT8U err;
    
        pdata = pdata;                                        //防止编译器报警
        
        while(1){
            RxMsg = (char *)OSMboxPend(TxMbox,0,&err);        //通过邮箱的方式从任务1处获得数据
            
            Uart_SendString(RxMsg);                            //将获得的数据通过串口打印,Uart_SendString()函数在工程其它文件,此处未给出
            
            OSMboxPost(AckMbox,(void *)1);                    //通过该邮箱发送应答信号给任务1,表明已成功接收到数据
        }
    }

     

  • 相关阅读:
    Java页面中文编码要转换两次encodeURI
    ajax用get刷新页面元素在IE下无效解决~~
    祝贺自己开博~~
    错误域控降级导致解析问题
    ELK 脚本自动化删除索引
    Windows针对子目录共享权限控制
    ES查询区分大小写
    Docker异常时区问题
    Docker自定义镜像无容器日志输出
    ELK时间戳
  • 原文地址:https://www.cnblogs.com/legion/p/7839759.html
Copyright © 2011-2022 走看看