uCOSii消息队列

news2024/11/22 1:09:04

消息队列管理(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、测试结果

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/600773.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Talk预告 | 罗格斯大学徐子昊:在域迁移学习中,用变分推理自动生成可解释的域索引

本期为TechBeat人工智能社区第501期线上Talk&#xff01; 北京时间5月31日(周三)20:00&#xff0c;罗格斯大学 在读博士生—徐子昊的Talk将准时在TechBeat人工智能社区开播&#xff01; 他与大家分享的主题是: “在域迁移学习中&#xff0c;用变分推理自动生成可解释的域索引…

Expeditors EDI需求详解

Expeditors是一家全球性的物流公司&#xff0c;成立于1979年&#xff0c;总部位于美国华盛顿州的西雅图。该公司提供海运、空运、货运代理、清关、仓储等一系列全球物流服务&#xff0c;并致力于通过数字化技术提高供应链的可见性和效率。Expeditors的客户遍及各行各业&#xf…

CMAKE变量与选择详解

目录 在 CMake 中&#xff0c;变量和选项是&#xff1a; CMake中的变量&#xff1a; 接下来是一个cmake的案例&#xff1a; 在CMake中定义和使用函数&#xff1a; 在 CMake 中&#xff0c;变量和选项是&#xff1a; 变量&#xff08;Variables&#xff09;&#xff1a; CMak…

chatgpt赋能python:Python函数查看快捷键:不可或缺的工具

Python函数查看快捷键&#xff1a;不可或缺的工具 Python是一门流行的编程语言&#xff0c;是数据分析、机器学习、人工智能等各种领域的首选语言。对于有10年Python编程经验的开发人员来说&#xff0c;Python函数查看快捷键可能是最熟悉的工具之一。因此&#xff0c;本篇文章…

k8s部署docker

1 环境准备 操作系统&#xff1a;centos7.9_x64 Docker&#xff1a;20-ce K8s&#xff1a;1.23 操作系统最小硬件配置&#xff08;在vmmare安装时需要选择&#xff09;&#xff1a;2核CPU、2G内存、20G硬盘 k8s-master&#xff1a;192.168.88.191 k8s-node1&#xff1a;192.…

chatgpt赋能python:Python冒泡排序算法详解

Python冒泡排序算法详解 介绍 冒泡排序是一种简单但相对较慢的排序算法。这个算法会重复地遍历要排序的数列&#xff0c;每次比较两个元素&#xff0c;如果它们的顺序错误就交换它们的位置&#xff0c;直到没有任何一对元素需要交换为止。这个算法由于排序过程中最大元素就像…

怎么用Excel VBA写一个excel批量合并的程序?

您可以按照以下VBA代码来实现把同一路径上的所有工作簿合并到同一个工作簿中&#xff1a; VBA Option Explicit Sub MergeWorkbooks() Dim path As String, fileName As String, sheet As Worksheet Dim targetWorkbook As Workbook, sourceWorkbook As Workbook Dim workshe…

建立可重复使用的自动测试过程

建立可重复使用的自动测试过程 在软件开发领域&#xff0c;自动化测试已经成为必不可少的一部分&#xff0c;它可以提高软件产品的质量、减少错误率、加快测试时间。但是&#xff0c;为了让自动测试过程更加高效和可重复使用&#xff0c;需要建立一套稳定的自动化测试框架。 自…

ES6: 模板字符串和箭头函数的基本使用

前言 本文主要介绍了ES6中模板字符串和箭头函数的基本使用 一、模板字符串 1、基本介绍 由反引号(在键盘Esc键的下面&#xff09;圈住的字符串即模板字符串举例&#xff1a; //普通字符串 const namehello console.log(name)//模板字符串 const name1world console.log(na…

前端js实现将数组某一项符合条件的对象,放到首位

哈喽 大家好啊 在日常前端开发需求中&#xff0c;总是会遇到开发数组&#xff0c;将某一项对象值&#xff0c;放到首位&#xff0c;让用户更好的去选择&#xff0c;比如省会城市优先等 我做的案例是需要将地区中的四川放到首位 以下是我的代码&#xff1a; 简单说明下思路&a…

蓝桥杯单片机PCF8591芯片ADC与DAC运行冲突解决

单片机型号&#xff1a;STC15F2K60S2 目录 文章附上工程下载地址&#xff1a; 在进行ADC与DAC测试时发现了如下冲突&#xff1a; 实验问题发现&#xff1a; 解决方案&#xff1a; 文章附上工程下载地址&#xff1a; https://download.csdn.net/download/qq_64257614/87854…

OpenWrt 安装“Alist 文件列表”挂载云盘

警告天翼云盘上传受限每天只有2GB 警告天翼云盘上传受限每天只有2GB 警告天翼云盘上传受限每天只有2GB 前言&#xff08;背景故事&#xff0c;没有干货&#xff09; 此前一直在用“阿里云盘-WebDAV”&#xff0c;用起来也挺好非常的方便&#xff0c;直到最近接触到“天翼云盘…

动态调整xxl_job下次执行时间

项目场景&#xff1a; 目前项目引入了 xxl-job 来跑定时任务&#xff0c;但是存在一个问题&#xff0c;项目执行结束的时间不固定&#xff0c;有峰值&#xff0c;在高峰期的时候会出现长阻塞一直排队等待&#xff0c;如图&#xff1a; 问题描述 需要做一种策略来解决长阻塞问…

区块链理财源码【互联网畜牧业养牛平台】带积分商城+抽奖+会员特权【亲测】

源码简介&#xff1a; 互联网畜牧业的养牛平台&#xff0c;非常火的区块链农业应用&#xff0c;是养殖业元宇宙的一种理财商业模式&#xff0c;农业类的其实都可以借鉴这种思路。当然了&#xff0c;玩法比较多样&#xff0c;不要做违法的事情就行。 代码已经简单亲测了一下&a…

linuxOPS基础_linux文本文件查看及统计

vi/vim vim文档编辑操作太多了,可以看这篇单独介绍vim的文章>https://blog.csdn.net/weixin_44368963/article/details/130963920 cat查看文件 命令&#xff1a;cat 作用&#xff1a;查看文件内容 语法&#xff1a;#cat 文件名称 ​ #cat 文件1 文件2 > 文件3 **特别注…

docker入门(1)----服务/镜像/容器/数据卷相关命令

安装 官网安装app命令行安装&#xff08;但是没有图形界面app&#xff09;brew install docker 架构 镜像&#xff08;Image&#xff09;&#xff1a;Docker 镜像&#xff08;Image&#xff09;&#xff0c;就相当于是一个 root 文件系统。比如官方镜像ubuntu:16.04 就包含了…

chatgpt赋能python:Python内置排序:快速高效的数据处理方式

Python内置排序&#xff1a;快速高效的数据处理方式 作为一种非常流行的编程语言&#xff0c;Python提供了很多高效、易于使用的内置功能&#xff0c;其中之一就是排序函数。通过使用内置的排序函数&#xff0c;Python工程师可以快速高效地处理各种不同类型的数据&#xff0c;…

什么是DAS/SAN/NAS

先上图 DAS DAS(Direct-attached Storage) 直连存储&#xff0c;这种存储设备通常是一个磁盘阵列柜&#xff0c;里面有多块磁盘&#xff0c;但不带RAID功能。 它与服务器主机之间的连接通常采用SCSI或者FC连接。DAS只能连接一台服务器&#xff0c;其它服务器无法共享该存储。 …

Redisson

文章目录 Redisson背景简介使用引入依赖配置类源代码 Redisson 背景 基于Redis(setnx)实现的分布式锁存在以下几个问题&#xff1a; 不可重入&#xff1a;同一个线程无法多次获取同一把锁 不可重试&#xff1a;获取锁只尝试一次就返回false&#xff0c;没有重试机制 超时释…

云服务器+minio+PicGo+Typora搭建个人图床实现typora鼠标右击上传图片。

搭建图床 服务器配置docker安装minio安装配置docker安装minio配置minio picgo配置下载picgopicgo配置去插件市场下载&#xff0c;minio配置 typora配置安装破解设置上传服务 服务器配置 本人用的是阿里云的轻量型云服务器&#xff0c;centos7.6&#xff0c;没有服务器的可以自…