uCOSii消息队列

消息队列管理(MESSAGE QUEUE MANAGEMENT)

1、消息队列定义

消息队列好比人们排队买票,排队的人好比是消息,每来一个人,都要到队伍的尾部去排队,叫添加一条消息到队列中。售票员卖票给先到的人,叫从对列中接收一条消息。这种队列处理方式叫先进先出。这个队伍的最大长度就是消息对列的容器

消息队列是一个数据流,是由多个数据块构成的串,像是一节节车厢,故称队列。其实就是把要传输的数据依次放在队列中,然后再依次读出,好比是数据搬家。

消息队列是一个存放消息的容器,它能存放多少条消息,每条消息的内容是什么,所以在创建消息队列时,要先指定好“消息队列的容器大小”,具体每条消息多少字节,没有被给出,但定义了一个指针,指向消息数据块的首地址,也就是说,每条消息是一个数据块。

pq-> OSQStart:消息队列容器的起始指针

pq->OSQEnd:消息队列容器的结束指针

pq->OSQIn:

按照先进先出方式,就是入列指针,是指针的指针,用来指向消息数据块地址;

pq->OSQOut:

按照先进先出方式,就是出列指针,是指针的指针,用来指向消息数据块地址;

按照后进先出方式,既是入列指针,也是出列指针,是指针的指针,用来指向消息数据块地址;

pq->OSQEntries:消息队列计数器,表示当前有多少条消息等待读取

pevent->OSEventType:事件类型

pevent->OSEventPtr://消息队列控制块指针

以上是我个人根据代码提炼出来的理解,可能和其他人理解有出入。

在程序中,要么使用先进先出方式,要么选择后进先出方式。两种方式都用,程序会乱,除非你能控制好。

应用场景:

在需要异步处理时,如:发送短信验证码

一次性无法处理的大块数据传输,就需要分流装载发送或接收。

2、创建消息队列

在创建消息队列指针之前,先要定义好消息容器的大小,并定义一个指针数组,用来存放”消息数据的指针”,如下定义

#define MessageQueueContainer_Size  12

//消息队列的容器大小,最多可以存放12条消息

void *MessageQueueContainer[MessageQueueContainer_Size];//定义消息队列的容器

用法:

MessageQueuePointer=OSQCreate(&MessageQueueContainer[0],MessageQueueContainer_Size);

//建立一个消息队列,其指针为MessageQueuePointer

3、消息队列几个很重要的函数

OS_EVENT  *OSQCreate (void **start, INT16U size)

INT8U  OSQPost (OS_EVENT  *pevent,  void  *pmsg)

void  *OSQPend (OS_EVENT  *pevent,  INT32U  timeout, INT8U  *perr)

INT8U  OSQPostFront (OS_EVENT  *pevent, void  *pmsg)

void  *OSQAccept (OS_EVENT  *pevent, INT8U  *perr)

INT8U  OSQFlush (OS_EVENT *pevent)

INT8U  OSQPostOpt (OS_EVENT  *pevent, void  *pmsg, INT8U  opt)

4、函数功能介绍

OSQCreate()建立一个消息队列,并返回消息队列指针

OSQPend()若有消息,则将消息队列的数据块首地址返回;若无消息,则挂起任务等待消息到来;

OSQAccept()若有消息,则将消息队列的数据块首地址返回,令perr =OS_ERR_NONE;若无消息,则令perr = OS_ERR_Q_EMPTY,且返回值为0

OSQFlush()清除消息对列中的所有消息,返回值为OS_ERR_NONE,表示操作正确

OSQPost()按照先入先出方式,添加一条消息到“消息队列容器”;若消息队列容器为空,则不入列,直接将消息发送给等待消息队列的任务

OSQPostFront()按照后入先出方式,添加一条消息到“消息队列容器”;若消息队列容器为空,则不入列,直接将消息发送给等待消息队列的任务

OSQPostOpt()

若消息队列容器已满,则直接将消息发给因消息队列而等待的任务,否则,将消息按照指定的方式入列

opt = OS_POST_OPT_BROADCAST=0x01群发消息,不用入列,直接把当前的消息发给因消息队列而等待的任务

若“消息队列容器满了”,就不用添加消息入列,返回值为OS_ERR_Q_FULL

若“消息队列容器没有满”且opt=OS_POST_OPT_FRONT,按照后入先出添加消息到队列中

若“消息队列容器没有满”且opt!=OS_POST_OPT_FRONT,按照先入先出添加消息到队列中

//返回值为OS_ERR_Q_FULL,表示“入列因消息队列容器已满而失败”

//返回值为OS_ERR_NONE,表示入列成功

5、读程序,分析函数功能

1) OS_EVENT  *OSQCreate (void **start, INT16U size)

//函数功能: 建立一个消息队列,并返回消息队列指针

// start消息队列容器的起始指针

// size消息队列容器的大小

OS_EVENT  *OSQCreate (void    **start,

                      INT16U    size)

{

    OS_EVENT  *pevent;

    OS_Q      *pq;

#if  OS_CRITICAL_METHOD == 3u

    OS_CPU_SR  cpu_sr = 0u;

#endif

#ifdef  OS_SAFETY_CRITICAL_IEC61508

if (OSSafetyCriticalStartFlag == OS_TRUE)

{

      OS_SAFETY_CRITICAL_EXCEPTION();

    }

#endif

if (OSIntNesting > 0u)

{

      return ((OS_EVENT *)0);

    }

    OS_ENTER_CRITICAL();//进入临界区(无法被中断打断),需要定义cpu_sr变量

pevent = OSEventFreeList;//来自系统

/*空闲的事件控制块指针保存到pevent中,将用作消息队列指针”*/

if (OSEventFreeList != (OS_EVENT *)0)

{//”空闲的事件控制块指针有效

      OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;

      //指向事件控制块的列表

}

    OS_EXIT_CRITICAL();//退出临界区(可以被中断打断)

if (pevent != (OS_EVENT *)0)

{//”空闲的事件控制块指针有效

        OS_ENTER_CRITICAL();//进入临界区(无法被中断打断),需要定义cpu_sr变量

        pq = OSQFreeList;/*指向消息队列控制块的列表*/

        if (pq != (OS_Q *)0) /*已经获取到空闲的队列控制块*/

        {//”消息队列控制块的列表指针有效

            OSQFreeList = OSQFreeList->OSQPtr;

            /*调节空闲列表指针指向下一个空闲列表*/

            OS_EXIT_CRITICAL();//退出临界区(可以被中断打断)

            pq->OSQStart = start;//初始化消息队列容器的起始指针

            pq->OSQEnd= &start[size]; //初始化消息队列容器的结束指针

            pq->OSQIn   = start;//初始化入列指针

            pq->OSQOut  = start; //初始化出列指针

            pq->OSQSize  = size; //初始化消息队列容器的大小

            pq->OSQEntries = 0u; //消息队列计数器

            pevent->OSEventType = OS_EVENT_TYPE_Q;//设置事件类型为消息队列

            pevent->OSEventCnt     = 0u;

            pevent->OSEventPtr     = pq;//消息队列控制块指针

#if OS_EVENT_NAME_EN > 0u

            pevent->OSEventName    = (INT8U *)(void *)"?";

#endif

            OS_EventWaitListInit(pevent);/*Initalize the wait list*/

        }

        else//”消息队列控制块的列表指针无效

        {

            pevent->OSEventPtr = (void *)OSEventFreeList;

            /* No, Return event control block on error */

            OSEventFreeList    = pevent;

            OS_EXIT_CRITICAL();//退出临界区(可以被中断打断)

            pevent = (OS_EVENT *)0;//创建消息队列失败

        }

    }

    return (pevent);

}

2)INT8U  OSQPost (OS_EVENT  *pevent,  void  *pmsg)

函数功能:按照先入先出方式,添加一条消息到“消息队列容器”;若消息队列容器为空,则不入列,直接将消息发送给等待消息队列的任务

// pevent为消息队列指针

// pmsg为准备入列的消息指针

//返回值为OS_ERR_NONE,表示“入列正确”

//返回值为OS_ERR_Q_FULL,表示“入列因消息队列容器已满而失败”

INT8U  OSQPost (OS_EVENT  *pevent,

                void      *pmsg)

{

    OS_Q      *pq;

#if  OS_CRITICAL_METHOD == 3u

    OS_CPU_SR  cpu_sr = 0u;

#endif

#if  OS_ARG_CHK_EN > 0u

if (pevent == (OS_EVENT *)0)

{//pevent指针为0

        return (OS_ERR_PEVENT_NULL);

    }

#endif

if (pevent->OSEventType != OS_EVENT_TYPE_Q)

{//事件类型不是消息队列类型

        return (OS_ERR_EVENT_TYPE);

}

    OS_ENTER_CRITICAL();//进入临界区(无法被中断打断),需要定义cpu_sr变量

if (pevent->OSEventGrp != 0u)

{//发现因消息队列而挂起的任务,或者有更高优先级任务在等待消息队列

//说明当前的消息队列是空的,非空的消息队列不会引起任务挂起

        (void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK);

        //消息不用入列,直接将pmsg所指向的数据块地址发送给等待任务

        OS_EXIT_CRITICAL();//退出临界区(可以被中断打断)

        OS_Sched();//有更高优先级在准备运行,执行任务调度

        return (OS_ERR_NONE);

    }

///没有发现因消息队列而挂起的任务///

    pq = (OS_Q *)pevent->OSEventPtr; //读取消息队列控制块指针

if (pq->OSQEntries  >=  pq->OSQSize)

{//”消息队列计数器超过消息队列容器的最大值”, 消息队列容器满了

        OS_EXIT_CRITICAL();//退出临界区(可以被中断打断)

        return (OS_ERR_Q_FULL);//不添加消息,返回OS_ERR_Q_FULL

    }

//消息队列容器没有满//

//按照先进先出方式添加消息/

    *pq->OSQIn++ = pmsg;//将消息添加到消息队列容器,入列指针1

pq->OSQEntries++;//消息队列计数器加1

if (pq->OSQIn == pq->OSQEnd)

{//入列指针到达消息队列容器的结束指针

        pq->OSQIn = pq->OSQStart;

     //入列指针设置为消息队列容器的起始指针

    }

    OS_EXIT_CRITICAL();//退出临界区(可以被中断打断)

    return (OS_ERR_NONE);

}

3) void  *OSQPend (OS_EVENT  *pevent,  INT32U  timeout, INT8U  *perr)

函数功能:若有消息,则将消息队列的数据块首地址返回;若无消息,则挂起任务等待消息到来;

// perr =OS_ERR_NONE,且返回值不为0,表示读到消息

timeout=0任务会一直挂起,直到收到新消息

timeout!=0任务在timeout个节拍内,若收到新消息,则退出,否则,超时退出消息消息接收

void  *OSQPend (OS_EVENT  *pevent,

                INT32U     timeout,

                INT8U     *perr)

{

    void      *pmsg;

    OS_Q      *pq;

#if  OS_CRITICAL_METHOD == 3u

    OS_CPU_SR  cpu_sr = 0u;

#endif

#ifdef OS_SAFETY_CRITICAL

if (perr == (INT8U *)0)

{//perr指针为0

       OS_SAFETY_CRITICAL_EXCEPTION();

    }

#endif

#if OS_ARG_CHK_EN > 0u

if (pevent == (OS_EVENT *)0)

{//pevent指针为0

        *perr = OS_ERR_PEVENT_NULL;

        return ((void *)0);

    }

#endif

if (pevent->OSEventType != OS_EVENT_TYPE_Q)

{//事件类型不是消息队列类型

        *perr = OS_ERR_EVENT_TYPE;

        return ((void *)0);

}

if (OSIntNesting > 0u)

{//如果是中断服务程序调用,则返回0

        *perr = OS_ERR_PEND_ISR;//中断服务程序不能挂起

        return ((void *)0);

    }

if (OSLockNesting > 0u)

{//调度器上锁访问

        *perr = OS_ERR_PEND_LOCKED;//当调度器上锁时,任务不能被挂起

         return ((void *)0);

}

    OS_ENTER_CRITICAL();//进入临界区(无法被中断打断),需要定义cpu_sr变量

pq = (OS_Q *)pevent->OSEventPtr; //读取消息队列控制块指针

if (pq->OSQEntries > 0u)

{//”消息队列计数器大于0,说明消息队列里有未读消息

        pmsg = *pq->OSQOut++;//出列指针保存到pmsg,然后将出列指针1

        pq->OSQEntries--; //”消息队列计数器1

        if (pq->OSQOut == pq->OSQEnd)

        {//出列指针到达消息队列容器的结束指针

            pq->OSQOut = pq->OSQStart;

//将出列指针设置为消息队列容器的起始指针

        }

        OS_EXIT_CRITICAL();//退出临界区(可以被中断打断)

        *perr = OS_ERR_NONE;

        return (pmsg);//读到消息

}

///”消息队列计数器等于0,说明消息队列里无可读消息///”

    OSTCBCur->OSTCBStat     |= OS_STAT_Q;//任务将挂起

    OSTCBCur->OSTCBStatPend  = OS_STAT_PEND_OK;

OSTCBCur->OSTCBDly       = timeout;//装载时间到TCB任务控制块

    OS_EventTaskWait(pevent);// 挂起任务,直到事件到来或时间超时

    OS_EXIT_CRITICAL();//退出临界区(可以被中断打断)

    OS_Sched();//有更高优先级在准备运行,执行任务调度

    OS_ENTER_CRITICAL();//进入临界区(无法被中断打断),需要定义cpu_sr变量

switch (OSTCBCur->OSTCBStatPend)

{

        case OS_STAT_PEND_OK://任务挂起OK,不再挂起或挂起完成

             pmsg =  OSTCBCur->OSTCBMsg;//保存列读取消息的指针,读到消息

            *perr =  OS_ERR_NONE;

             break;

        case OS_STAT_PEND_ABORT://任务等待失败

             pmsg = (void *)0;

            *perr =  OS_ERR_PEND_ABORT;

             break;

        case OS_STAT_PEND_TO://任务挂起导致时间超时溢出

        default:

             OS_EventTaskRemove(OSTCBCur, pevent);

             pmsg = (void *)0;

            *perr =  OS_ERR_TIMEOUT;

             break;

}

    OSTCBCur->OSTCBStat =  OS_STAT_RDY; //设置任务进入准备状态

OSTCBCur->OSTCBStatPend  = OS_STAT_PEND_OK; //清除挂起状态

    OSTCBCur->OSTCBEventPtr      = (OS_EVENT  *)0;//清除当前的事件指针

#if (OS_EVENT_MULTI_EN > 0u)

    OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;

#endif

OSTCBCur->OSTCBMsg = (void *)0; //清除接收消息

    OS_EXIT_CRITICAL();//退出临界区(可以被中断打断)

    return (pmsg);

}

4)INT8U  OSQPostFront (OS_EVENT  *pevent, void  *pmsg)

函数功能:按照后入先出方式,添加一条消息到“消息队列容器”;若消息队列容器为空,则不入列,直接将消息发送给等待消息队列的任务

// pevent为消息队列指针

// pmsg为准备入列的消息指针

//返回值为OS_ERR_NONE,表示“入列正确”

//返回值为OS_ERR_Q_FULL,表示“入列因消息队列容器已满而失败”

INT8U  OSQPostFront (OS_EVENT  *pevent,

                     void      *pmsg)

{

    OS_Q      *pq;

#if OS_CRITICAL_METHOD == 3u

    OS_CPU_SR  cpu_sr = 0u;

#endif

#if OS_ARG_CHK_EN > 0u

if (pevent == (OS_EVENT *)0)

{

        return (OS_ERR_PEVENT_NULL);

    }

#endif

if (pevent->OSEventType != OS_EVENT_TYPE_Q)

{

        return (OS_ERR_EVENT_TYPE);

}

    OS_ENTER_CRITICAL();//进入临界区(无法被中断打断),需要定义cpu_sr变量

if (pevent->OSEventGrp != 0u)

{//发现因消息队列而挂起的任务,或者有更高优先级任务在等待消息队列

//说明当前的消息队列是空的,非空的消息队列不会引起任务挂起

        (void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK);

//消息不用入列,直接将pmsg所指向的数据块地址发送给等待任务

    OS_EXIT_CRITICAL();//退出临界区(可以被中断打断)

        OS_Sched();//有更高优先级在准备运行,执行任务调度

        return (OS_ERR_NONE);

}

    pq = (OS_Q *)pevent->OSEventPtr; //读取消息队列控制块指针

if (pq->OSQEntries >= pq->OSQSize)

{//”消息队列计数器超过消息队列容器的最大值”, 消息队列容器满了

        OS_EXIT_CRITICAL();//退出临界区(可以被中断打断)

        return (OS_ERR_Q_FULL); //不添加消息,返回OS_ERR_Q_FULL

}

//消息队列容器没有满//

//按照后入先出方式添加消息/

if (pq->OSQOut == pq->OSQStart)

{//出列指针等于消息队列容器的起始指针

        pq->OSQOut = pq->OSQEnd;

//出列指针设置为消息队列容器的结束指针

    }

    pq->OSQOut--;//”出列指针1

    *pq->OSQOut = pmsg; //将消息添加到消息队列容器

    pq->OSQEntries++; //消息队列计数器加1

OS_EXIT_CRITICAL();//退出临界区(可以被中断打断)

    return (OS_ERR_NONE);

}

5)void  *OSQAccept (OS_EVENT  *pevent, INT8U  *perr)

函数功能:若有消息,则将消息队列的数据块首地址返回,令perr =OS_ERR_NONE;若无消息,则令perr = OS_ERR_Q_EMPTY,且返回值为0

// pevent为消息队列指针

// perr =OS_ERR_NONE,且返回值不为0,表示读到消息

void  *OSQAccept (OS_EVENT  *pevent,

                  INT8U     *perr)

{

    void      *pmsg;

    OS_Q      *pq;

#if OS_CRITICAL_METHOD == 3u

    OS_CPU_SR  cpu_sr = 0u;

#endif

#ifdef OS_SAFETY_CRITICAL

if (perr == (INT8U *)0)

{ //perr指针为0

        OS_SAFETY_CRITICAL_EXCEPTION();

    }

#endif

#if OS_ARG_CHK_EN > 0u

if (pevent == (OS_EVENT *)0)

{//pevent指针为0

        *perr = OS_ERR_PEVENT_NULL;

        return ((void *)0);

    }

#endif

if (pevent->OSEventType != OS_EVENT_TYPE_Q)

{//事件类型不是消息队列类型

        *perr = OS_ERR_EVENT_TYPE;

        return ((void *)0);

}

    OS_ENTER_CRITICAL();//进入临界区(无法被中断打断),需要定义cpu_sr变量

pq = (OS_Q *)pevent->OSEventPtr; //读取消息队列控制块指针

if (pq->OSQEntries > 0u)

{//“消息队列计数器大于0,说明消息队列中有消息

        pmsg = *pq->OSQOut++;//出列指针保存到pmsg,然后将出列指针1

        pq->OSQEntries--;//“消息队列计数器1

        if (pq->OSQOut == pq->OSQEnd)

{//出列指针到达消息队列容器的结束指针

            pq->OSQOut = pq->OSQStart;

//将出列指针设置为消息队列容器的起始指针

        }

        *perr = OS_ERR_NONE;

}

else

{//“消息队列计数器大于0,说明消息队列中没有消息

        *perr = OS_ERR_Q_EMPTY;

        pmsg  = (void *)0;

}

    OS_EXIT_CRITICAL();//退出临界区(可以被中断打断)

    return (pmsg);

}

6)INT8U  OSQFlush (OS_EVENT *pevent)

//函数功能:清除消息对列中的所有消息,返回值为OS_ERR_NONE,表示操作正确

// pevent为消息队列指针

INT8U  OSQFlush (OS_EVENT *pevent)

{

    OS_Q      *pq;

#if OS_CRITICAL_METHOD == 3u

    OS_CPU_SR  cpu_sr = 0u;

#endif

#if OS_ARG_CHK_EN > 0u

if (pevent == (OS_EVENT *)0)

{//pevent指针为0

return (OS_ERR_PEVENT_NULL);

    }

if (pevent->OSEventType != OS_EVENT_TYPE_Q)

{//事件类型为消息队列类型

        return (OS_ERR_EVENT_TYPE);

    }

#endif

    OS_ENTER_CRITICAL();//进入临界区(无法被中断打断),需要定义cpu_sr变量

    pq= (OS_Q *)pevent->OSEventPtr; //读取消息队列控制块指针

    pq->OSQIn  = pq->OSQStart; //设置入列指针消息队列容器的起始指针

    pq->OSQOut = pq->OSQStart; //设置出列指针””消息队列容器的起始指针

    pq->OSQEntries = 0u;       //设置消息队列计数器0

    OS_EXIT_CRITICAL();

    return (OS_ERR_NONE);

}

7)INT8U  OSQPostOpt (OS_EVENT  *pevent, void  *pmsg, INT8U  opt)

函数功能:若消息队列容器已满,则直接将消息发给因消息队列而等待的任务,否则,将消息按照指定的方式入列

opt = OS_POST_OPT_BROADCAST=0x01群发消息,不用入列,直接把当前的消息发给因消息队列而等待的任务

若“消息队列容器满了”,就不用添加消息入列,返回值为OS_ERR_Q_FULL

若“消息队列容器没有满”且opt=OS_POST_OPT_FRONT,按照后入先出添加消息到队列中

若“消息队列容器没有满”且opt!=OS_POST_OPT_FRONT,按照先入先出添加消息到队列中

//返回值为OS_ERR_Q_FULL,表示“入列因消息队列容器已满而失败”

//返回值为OS_ERR_NONE,表示入列成功

INT8U  OSQPostOpt (OS_EVENT  *pevent,

                   void      *pmsg,

                   INT8U      opt)

{

    OS_Q      *pq;

#if OS_CRITICAL_METHOD == 3u

    OS_CPU_SR  cpu_sr = 0u;

#endif

#if OS_ARG_CHK_EN > 0u

if (pevent == (OS_EVENT *)0)

{//pevent指针为0,不允许

        return (OS_ERR_PEVENT_NULL);

    }

#endif

if (pevent->OSEventType != OS_EVENT_TYPE_Q)

{//事件类型不是消息队列类型

        return (OS_ERR_EVENT_TYPE);

    }

    OS_ENTER_CRITICAL();//进入临界区(无法被中断打断),需要定义cpu_sr变量

if (pevent->OSEventGrp != 0x00u)

{//发现因消息队列而挂起的任务,或者有更高优先级任务在等待消息队列

//说明当前的消息队列是空的,非空的消息队列不会引起任务挂起

      if ((opt & OS_POST_OPT_BROADCAST) != 0x00u)

      {//需要群发消息

         while (pevent->OSEventGrp != 0u)

         {//发现因消息队列而挂起的任务

           (void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK);

           //消息不用入列,直接将pmsg所指向的数据块地址发送给等待任务

          }

        }

        else//不需要群发消息

        {

          (void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK);

          //消息不用入列,直接将pmsg所指向的数据块地址发送给等待任务

        }

        OS_EXIT_CRITICAL();//退出临界区(可以被中断打断)

        if ((opt & OS_POST_OPT_NO_SCHED) == 0u)

        {

            OS_Sched();//发现有更高优先级的任务在企图运行,执行任务调度

        }

        return (OS_ERR_NONE);

}

///没有发现因消息队列而挂起的任务///

pq = (OS_Q *)pevent->OSEventPtr; //读取消息队列控制块指针

if (pq->OSQEntries >= pq->OSQSize)

{//”消息队列计数器超过消息队列容器的最大值”, 消息队列容器满了

        OS_EXIT_CRITICAL();//退出临界区(可以被中断打断)

        return (OS_ERR_Q_FULL); //不添加消息,返回OS_ERR_Q_FULL

    }

//消息队列容器没有满//

if ((opt & OS_POST_OPT_FRONT) != 0x00u)

{//按照后入先出方式添加消息

        if (pq->OSQOut == pq->OSQStart)

        {//出列指针等于消息队列容器的起始指针

            pq->OSQOut = pq->OSQEnd;

//出列指针设置为消息队列容器的结束指针

        }

        pq->OSQOut--;//”出列指针1

        *pq->OSQOut = pmsg; //将消息添加到消息队列容器

}

else

{//按照FIFO先入先出方式添加消息

        *pq->OSQIn++ = pmsg; //将消息添加到消息队列容器,入列指针1

        if (pq->OSQIn == pq->OSQEnd)

        {//入列指针到达消息队列容器的结束指针

            pq->OSQIn = pq->OSQStart;

         //入列指针设置为消息队列容器的起始指针

        }

}

pq->OSQEntries++;//消息队列计数器加1

    OS_EXIT_CRITICAL();//退出临界区(可以被中断打断)

    return (OS_ERR_NONE);

}

6、FIFO程序举例

#include "FIFO_SendData_Task.h"
#include "delay.h"
#include "stdio.h"  //getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()

#include "key.h"

#include "My_Task_Priority.h"
//#include "ucos_ii.h"

const char FIFO_SendData_Task_rn_REG[]="\r\n";
const char FIFO_SendData_Task_REG[]="FIFO_SendData_Task:";
const char Queue_is_FULL_REG[]="Queue is FULL";

void FIFO_SendData_Task(void *pdata);

char SendMessageBuffer[10];//每条消息为一个字节
u8 NumberOfMessage;//存放发送消息数量

//FIFO_SendData_Task任务
void FIFO_SendData_Task(void *pdata)
{	
	u8 cnt,i;
	u8 err;

  strcpy(SendMessageBuffer,"123456789");
	NumberOfMessage=strlen(SendMessageBuffer);//求"发送消息数量"
	cnt=0;
	while(1)
	{
		OSTimeDlyHMSM(0,0,0,1000);//延时1000ms
		cnt++;

    if(cnt>2)//时间到,则发送消息
		{
			for(i=0;i<NumberOfMessage;)//数据按照先进先出方式入列
			{
				printf("%s",FIFO_SendData_Task_rn_REG);
				printf("%s",FIFO_SendData_Task_REG);
				printf("%c",SendMessageBuffer[i]);//打印发送消息

			  err=OSQPost(MessageQueuePointer,&SendMessageBuffer[i]);
			  //按照先进先出方式,添加一条消息到“消息队列容器”;若消息队列容器为空,则不入列,直接将消息发送给”等待消息队列的任务”;
			  //返回值为OS_ERR_NONE,表示“入列正确”
			  if(err==OS_ERR_NONE)//入列正确
			  {
					i++;
			  }
				if(err==OS_ERR_Q_FULL)//消息队列已经满了
				{
					printf("%s",FIFO_SendData_Task_rn_REG);
					printf("%s",Queue_is_FULL_REG);
				}
		  }
			cnt=0;
		}
	}
}
#include "FIFO_ReceiveData_Task.h"
#include "stdio.h"  //getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()

#include "LED.h"

#include "My_Task_Priority.h"
#include "FIFO_SendData_Task.h"

void FIFO_ReceiveData_Task(void *pdata);

const char FIFO_ReceiveData_Task_rn_REG[]="\r\n";
const char FIFO_ReceiveData_Task_REG[]="FIFO_ReceiveData_Task:";


//FIFO_ReceiveData_Task任务
void FIFO_ReceiveData_Task(void *pdata)
{
	u8 err;
	char  *p;
	u32 timeout;

	while(1)
	{
		timeout=0;
		p=OSQPend(MessageQueuePointer,timeout,&err);
    //若有消息,则将消息队列的数据块首地址返回;若无消息,则挂起任务等待消息到来;
    //err =OS_ERR_NONE,且返回值不为0,表示读到消息
    //timeout=0任务会一直挂起,直到收到新消息
    //timeout!=0任务在timeout个节拍内,若收到新消息,则退出,否则,超时退出消息消息接收
		if(err==OS_ERR_NONE && p!=NULL)//读到消息
		{
			printf("%s",FIFO_ReceiveData_Task_rn_REG);
			printf("%s",FIFO_ReceiveData_Task_REG);
			printf("%c",*p);//打印接收到的消息
		}
//		OSTimeDlyHMSM(0,0,0,1);//延时1000ms
	}
}

 

#include "Start_Task.h"
#include "stdio.h"  //getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()

#include "LED.h"

#include "My_Task_Priority.h"
#include "FIFO_ReceiveData_Task.h"
#include "FIFO_SendData_Task.h"

void Start_Task(void *pdata);

const char Start_Task_rn_REG[]="\r\n";
const char Start_Task_Initialise_REG[]="Start_Task Initialise";
//Start_Task任务
void Start_Task(void *pdata)
{
	OS_CPU_SR cpu_sr=0;
	pdata = pdata;

	printf("%s",Start_Task_rn_REG);
	printf("%s",Start_Task_Initialise_REG);

	OS_ENTER_CRITICAL();   //进入临界区(无法被中断打断),需要定义cpu_sr变量
	MessageQueuePointer=OSQCreate(&MessageContainerArray[0],MessageContainerArray_Size);
	//建立一个消息队列,其指针为MessageQueuePointer
	//MessageContainerArray[0],"消息容器数组"的首地址
	//MessageContainerArray_Size,消息容器的大小

	OSTaskCreate( FIFO_ReceiveData_Task,/* 函数指针*/
	              (void *)0,/* 建立任务时,传递的参数*/
								(OS_STK*)&FIFO_ReceiveData_TASK_STACK[FIFO_ReceiveData_TASK_STACK_SIZE-1],/* 指向堆栈任务栈顶的指针*/
								FIFO_ReceiveData_TASK_PRIORITY/* 任务优先级*/
							);						   
	OSTaskCreate( FIFO_SendData_Task,/* 函数指针*/
								(void *)0,/* 建立任务时,传递的参数*/
								(OS_STK*)&FIFO_SendData_TASK_STACK[FIFO_SendData_TASK_STACK_SIZE-1],/* 指向堆栈任务栈顶的指针*/
								FIFO_SendData_TASK_PRIORITY/* 任务优先级*/
							);
	
	//OSTaskSuspend(START_TASK_PRIO);	//挂起起始任务Start_Task(),但不删除
	OSTaskDel(OS_PRIO_SELF); //删除自己
	OS_EXIT_CRITICAL();		//退出临界区(可以被中断打断)
}

 7、LIFO程序举例

#include "LIFO_SendData_Task.h"
#include "delay.h"
#include "stdio.h"  //getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()

#include "key.h"

#include "My_Task_Priority.h"
//#include "ucos_ii.h"

const char LIFO_SendData_Task_rn_REG[]="\r\n";
const char LIFO_SendData_Task_REG[]="LIFO_SendData_Task:";
const char Queue_is_FULL_REG[]="Queue is FULL";

void LIFO_SendData_Task(void *pdata);

char SendMessageBuffer[10];//每条消息为一个字节
u8 NumberOfMessage;//存放发送消息数量

//LIFO_SendData_Task任务
void LIFO_SendData_Task(void *pdata)
{	
	u8 cnt,i;
	u8 err;

  strcpy(SendMessageBuffer,"123456789");
	NumberOfMessage=strlen(SendMessageBuffer);
	cnt=0;
	while(1)
	{
		OSTimeDlyHMSM(0,0,0,1000);//延时1000ms

		if(MessageFlag==0)//消息没有发送完成
		{
		  cnt++;
      if(cnt>2)
		  {
			  for(i=0;i<NumberOfMessage;)//数据按照先进先出方式入列
			  {
				  printf("%s",LIFO_SendData_Task_rn_REG);
				  printf("%s",LIFO_SendData_Task_REG);
				  printf("%c",SendMessageBuffer[i]);//打印发送消息
			    err=OSQPostFront(MessageQueuePointer,(void*)&SendMessageBuffer[i]);
			    //按照后入先出方式,添加一条消息到“消息队列容器”;若消息队列容器为空,则不入列,直接将消息发送给”等待消息队列的任务”;
			    //返回值为OS_ERR_NONE,表示“入列正确”
			    if(err==OS_ERR_NONE)//入列正确
			    {
					  i++;
			    }
		    }
			  MessageFlag=1;//建立"消息发送完成"标志
			  cnt=0;
		  }
	  }
	}
}
#include "LIFO_ReceiveData_Task.h"
#include "stdio.h"  //getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()

#include "My_Task_Priority.h"

void LIFO_ReceiveData_Task(void *pdata);

const char LIFO_ReceiveData_Task_rn_REG[]="\r\n";
const char LIFO_ReceiveData_Task_REG[]="LIFO_ReceiveData_Task:";

u8 Get_NumberOfMessage(OS_EVENT *pevent)
{
	u8 x;
    OS_Q      *pq;
#if OS_CRITICAL_METHOD == 3u
    OS_CPU_SR  cpu_sr = 0u;
#endif


    OS_ENTER_CRITICAL();
    pq = (OS_Q *)pevent->OSEventPtr;      /* Point to queue storage structure              */
    x=pq->OSQEntries;
    OS_EXIT_CRITICAL();
    return (x);
}

//LIFO_ReceiveData_Task任务
//由于使用OSQPend(),所以该任务不能使用OSTimeDlyHMSM()
void LIFO_ReceiveData_Task(void *pdata)
{
	u8 err;
	void  *p;

	while(1)
	{
    if(MessageFlag)//消息发送完成,允许接收
		{
			p=OSQAccept(MessageQueuePointer,&err);
      //若有消息,则将消息队列的数据块首地址返回,令perr =OS_ERR_NONE;若无消息,则令err = OS_ERR_Q_EMPTY,且返回值为0
      //pevent为消息队列指针
      //perr =OS_ERR_NONE,且返回值不为0,表示读到消息
		  if(err==OS_ERR_NONE && p!=NULL)//读到消息
		  {
			  printf("%s",LIFO_ReceiveData_Task_rn_REG);
			  printf("%s",LIFO_ReceiveData_Task_REG);
			  printf("%c",*(char*)(p) );
		  }
			if(err==OS_ERR_Q_EMPTY) MessageFlag=0;//清除"消息发送完成"标志
	  }
		else OSTimeDlyHMSM(0,0,0,1000);//延时1000ms
	}
}
#include "Start_Task.h"
#include "stdio.h"  //getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()

#include "LED.h"

#include "My_Task_Priority.h"
#include "LIFO_ReceiveData_Task.h"
#include "LIFO_SendData_Task.h"

void Start_Task(void *pdata);

const char Start_Task_rn_REG[]="\r\n";
const char Start_Task_Initialise_REG[]="Start_Task Initialise";
//Start_Task任务
void Start_Task(void *pdata)
{
	OS_CPU_SR cpu_sr=0;
	pdata = pdata;

	printf("%s",Start_Task_rn_REG);
	printf("%s",Start_Task_Initialise_REG);

	OS_ENTER_CRITICAL();   //进入临界区(无法被中断打断),需要定义cpu_sr变量
	MessageQueuePointer=OSQCreate(&MessageContainerArray[0],MessageContainerArray_Size);
	//建立一个消息队列,其指针为MessageQueuePointer
	//MessageContainerArray[0],"消息容器数组"的首地址
	//MessageContainerArray_Size,消息容器的大小
	MessageFlag=0;

	OSTaskCreate( LIFO_ReceiveData_Task,/* 函数指针*/
	              (void *)0,/* 建立任务时,传递的参数*/
								(OS_STK*)&LIFO_ReceiveData_TASK_STACK[LIFO_ReceiveData_TASK_STACK_SIZE-1],/* 指向堆栈任务栈顶的指针*/
								LIFO_ReceiveData_TASK_PRIORITY/* 任务优先级*/
							);						   
	OSTaskCreate( LIFO_SendData_Task,/* 函数指针*/
								(void *)0,/* 建立任务时,传递的参数*/
								(OS_STK*)&LIFO_SendData_TASK_STACK[LIFO_SendData_TASK_STACK_SIZE-1],/* 指向堆栈任务栈顶的指针*/
								LIFO_SendData_TASK_PRIORITY/* 任务优先级*/
							);
	
	//OSTaskSuspend(START_TASK_PRIO);	//挂起起始任务Start_Task(),但不删除
	OSTaskDel(OS_PRIO_SELF); //删除自己
	OS_EXIT_CRITICAL();		//退出临界区(可以被中断打断)
}

8、任务优先级及相关变量 

#include "My_Task_Priority.h"

OS_STK START_TASK_STACK[START_TASK_STACK_SIZE]; //START_TASK任务堆栈
OS_STK LIFO_ReceiveData_TASK_STACK[LIFO_ReceiveData_TASK_STACK_SIZE];   //LIFO_ReceiveData_TASK任务堆栈
__align(8) OS_STK LIFO_SendData_TASK_STACK[LIFO_SendData_TASK_STACK_SIZE];
//LIFO_SendData_TASK任务堆栈
//如果任务中使用printf来打印浮点数据的话一点要8字节对齐

OS_EVENT *MessageQueuePointer;//定义一个"消息队列事件指针"
void *MessageContainerArray[MessageContainerArray_Size];//"消息容器数组"用来存放"消息指针",和"栈"差不多
u8 MessageFlag;//"消息发送完成"标志
//My_Task_Priority.h
#ifndef __MY_TASK_PRIORITY_H
#define __MY_TASK_PRIORITY_H

#include "includes.h"

//任务的优先级资源由操作系统提供,以μC/OS-II为例,共有64个优先级,优先级的高低按编号从0(最高)到63(最低)排序;

/*
为了保证“启动任务”能够连续运行,必须将“启动任务”的优先级选择为最高。
否则,当“启动任务”创建一个优先级高于自己的任务时,刚刚创建的任务就
会立即进入运行状态,而与这个任务关联的其它任务可能还没有创建,它使
用的通信工具也还没有创建,系统必然出错。
*/

#define START_TASK_PRIORITY      4   //设置START_TASK任务优先级,开始任务的优先级设置为最高
#define START_TASK_STACK_SIZE   192  //设置START_TASK任务堆栈大小,为8的倍数
extern OS_STK START_TASK_STACK[START_TASK_STACK_SIZE]; //START_TASK任务堆栈

#define LIFO_ReceiveData_TASK_PRIORITY       5   //设置LIFO_ReceiveData_TASK任务优先级为5
#define LIFO_ReceiveData_TASK_STACK_SIZE  	 56  //设置LIFO_ReceiveData_TASK任务堆栈大小为56,为8的倍数
extern OS_STK LIFO_ReceiveData_TASK_STACK[LIFO_ReceiveData_TASK_STACK_SIZE];  //LIFO_ReceiveData_TASK任务堆栈

#define LIFO_SendData_TASK_PRIORITY        6   //设置LIFO_SendData_TASK任务优先级为7 
#define LIFO_SendData_TASK_STACK_SIZE      56  //设置LIFO_SendData_TASK任务堆栈大小为56,为8的倍数
extern OS_STK LIFO_SendData_TASK_STACK[LIFO_SendData_TASK_STACK_SIZE];    //LIFO_SendData_TASK任务堆栈

extern OS_EVENT *MessageQueuePointer;//定义一个消息队列指针
#define MessageContainerArray_Size  12  //消息容器的大小
extern void *MessageContainerArray[MessageContainerArray_Size];//"消息容器数组"用来存放"消息指针"
extern u8 MessageFlag;//"消息发送完成"标志
#endif

 9、测试结果

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值