LiteOS消息队列

一、消息队列的基本概念

LiteOS提供消息队列,用于提供类似于数组的功能,用于传输数据。

任务或中断服务程序将消息放入消息队列,此时可以有一个或多个读取消息的任务去读取消息队列的数据。

如果队列为空,读取该任务被阻塞,可自定义阻塞时间,如果该任务等待时间超过了阻塞时间,自动转为就绪态。

消息队列满足先进先出(FIFO)的原则,也支持后进先出(LIFO)的原则。同时读队列和写队列还支持超时机制

二、消息队列的运行机制

创建队列时,根据传入的队列长度和消息节点大小,开辟内存空间,并初始化消息队列的相关信息,返回队列ID

消息队列控制块中,会维护一个消息头节点usQueueHead和消息尾节点usQueueTail位置变量,头节点表示队列中被占用消息节点的起始位置,尾节点表示占用消息节点的结束位置。队列刚创建时,两个节点均指向队列起始位置

写队列前,先判断队列是否可写(根据usReadWriteable判断),队列未满时可写。写队列时,根据尾节点找到消息节点末尾的空闲节点作为消息写入区。如果尾节点已经指向队列尾,则采用回卷方式(把队列看成一个圆圈)进行操作

读队列前,判断是否有消息读取(根据usReadWriteable),队列为空时不能操作,为空时读取将引起任务挂起。读队列时根据头节点找到最先写入对的消息节点进行读取,如果头节点指向队列尾,采用回卷操作

删除队列时,根据传入的队列ID,将队列置为未使用状态,释放内存空间,将队列头设置为初始状态

消息队列读写消息示意图如下所示

三、消息队列的传输机制

消息队列中有多个消息节点,消息节点的大小在创建队列时由用户指定,对数据的传递有复制和引用两种方式,复制的数据不影响原数据,引用的数据影响原数据。

四、消息队列的阻塞机制

阻塞机制用于保护各任务对消息队列进行正常读写操作

4.1 出队阻塞(读阻塞)

A对队列进行读取时,假如队列为空,A有三个选择:1.不阻塞,不等待消息到来 2.阻塞A,定义等待时间,时间内消息来到恢复就绪态读取消息,超时则恢复就绪态继续运行 3.A阻塞,一直等待到消息到来,直到读取完成

4.2 入队阻塞(写阻塞)

A向队列写入消息,假如队列已满,A被阻塞,直到允许入队时才能成功写入。系统根据用户定义的阻塞超时时间将任务阻塞,超时了还不能写入,返回错误代码,解除阻塞状态。只有在任务中写入消息才允许带有阻塞,中断中写入消息不允许带有阻塞。

多个任务阻塞在一个消息队列中时,阻塞的任务按照优先级排序,优先级高的优先获得队列访问权

五、常见队列错误代码

在工程的los_queue.h文件中,定义了错误代码的说明

六、常用消息队列的函数

使用消息队列的流程:创建队列,得到队列ID—>写消息—>读消息—>删除队列

6.1 消息队列创建函数LOS_QueueCreate

创建成功的队列,队列长度和消息节点的大小无法更改。初始化队列时,系统会为控制块分配对应的内存空间,控制块保存消息队列的基本信息:队列指针、队列状态、消息个数、节点大小、队列ID、消息头结点位置、消息尾结点位置等

LITE_OS_SEC_TEXT_INIT UINT32 LOS_QueueCreate(CHAR *pcQueueName,//消息队列名
                                          UINT16 usLen,//队列长度,1~0xFFFF
                                          UINT32 *puwQueueID,//消息队列ID
                                          UINT32 uwFlags,//队列模式
                                          UINT16 usMaxMsgSize )//消息节点大小(字节),1~(0xFFFF-4)
{
    QUEUE_CB_S      *pstQueueCB;
    UINTPTR         uvIntSave;
    LOS_DL_LIST     *pstUnusedQueue;
    UINT8           *pucQueue;
    UINT16          usMsgSize = usMaxMsgSize + sizeof(UINT32);
//(1)传进来的队列名称和队列模式转换为空类型,未使用到这两个参数
    (VOID)pcQueueName;
    (VOID)uwFlags;
//(2)如果ID为空,返回错误代码
    if (NULL == puwQueueID)
    {
        return LOS_ERRNO_QUEUE_CREAT_PTR_NULL;
    }

    if(usMaxMsgSize > OS_NULL_SHORT -4)
    {
        return LOS_ERRNO_QUEUE_SIZE_TOO_BIG;
    }
//(3)如果消息节点过大或为0,返回错误代码
    if ((0 == usLen) || (0 == usMaxMsgSize))
    {
        return LOS_ERRNO_QUEUE_PARA_ISZERO;
    }

//(4)为队列分配内存,根据队列长度和消息节点大小进行动态分配
    pucQueue = (UINT8 *)LOS_MemAlloc(m_aucSysMem0, usLen * usMsgSize);
    if (NULL == pucQueue)
    {
        return LOS_ERRNO_QUEUE_CREATE_NO_MEMORY;
    }
//(5)判断是否可创建队列,因为系统配置中定义了最大可创建的队列数量
    uvIntSave = LOS_IntLock();
    if (LOS_ListEmpty(&g_stFreeQueueList))
    {
        LOS_IntRestore(uvIntSave);
        (VOID)LOS_MemFree(m_aucSysMem0, pucQueue);
        return LOS_ERRNO_QUEUE_CB_UNAVAILABLE;
    }
//(6)从系统管理的空闲消息队列控制块列表中取下一个消息队列控制块,表示消息队列已被创建
    pstUnusedQueue = LOS_DL_LIST_FIRST(&(g_stFreeQueueList));
    LOS_ListDelete(pstUnusedQueue);
    pstQueueCB = (GET_QUEUE_LIST(pstUnusedQueue));
//(7)配置队列的具体过程,配置队列长度
    pstQueueCB->usQueueLen = usLen;
//(8)配置消息节点大小
    pstQueueCB->usQueueSize = usMsgSize;
//(9)存放消息的起始地址pucQueue,将消息队列的状态设置为可用
    pstQueueCB->pucQueue = pucQueue;
    pstQueueCB->usQueueState = OS_QUEUE_INUSED;
//(10)初始化可读消息的个数为0
    pstQueueCB->usReadWriteableCnt[OS_QUEUE_READ]  = 0;
//(11)初始化可写的消息个数为uslen
    pstQueueCB->usReadWriteableCnt[OS_QUEUE_WRITE] = usLen;
//(12)头指针和为指针都为0
    pstQueueCB->usQueueHead = 0;
    pstQueueCB->usQueueTail = 0;
//(13)初始化读写操作的消息控件链表
    LOS_ListInit(&pstQueueCB->stReadWriteList[OS_QUEUE_READ]);
    LOS_ListInit(&pstQueueCB->stReadWriteList[OS_QUEUE_WRITE]);
    LOS_ListInit(&pstQueueCB->stMemList);
    LOS_IntRestore(uvIntSave);
//(14)将ID返还给用户
    *puwQueueID = pstQueueCB->usQueueID;

    return LOS_OK;
}

6.2 消息队列删除函数

根据ID删除消息队列,队列在使用中或阻塞中无法删除,未创建的队列也无法删除

LITE_OS_SEC_TEXT_INIT UINT32 LOS_QueueDelete(UINT32 uwQueueID)
{
    QUEUE_CB_S *pstQueueCB;
    UINT8 *pucQueue = NULL;
    UINTPTR  uvIntSave;
    UINT32 uwRet;
//(1)判断ID有效性
    if (uwQueueID >= LOSCFG_BASE_IPC_QUEUE_LIMIT)
    {
        return LOS_ERRNO_QUEUE_NOT_FOUND;
    }

    uvIntSave = LOS_IntLock();
//(2)根据ID获取队列控制块状态,如果队列未使用,返回错误
    pstQueueCB = (QUEUE_CB_S *)GET_QUEUE_HANDLE(uwQueueID);
    if (OS_QUEUE_UNUSED == pstQueueCB->usQueueState)
    {
        uwRet = LOS_ERRNO_QUEUE_NOT_CREATE;
        goto QUEUE_END;
    }
//(3)如果有任务在等待消息队列中的消息,则无法删除
    if (!LOS_ListEmpty(&pstQueueCB->stReadWriteList[OS_QUEUE_READ]))
    {
        uwRet = LOS_ERRNO_QUEUE_IN_TSKUSE;
        goto QUEUE_END;
    }
//(4)如果有任务在等待写入消息到队列中,则无法删除
    if (!LOS_ListEmpty(&pstQueueCB->stReadWriteList[OS_QUEUE_WRITE]))
    {
        uwRet = LOS_ERRNO_QUEUE_IN_TSKUSE;
        goto QUEUE_END;
    }
//(5)如果队列非空,系统为了保证任务获得资源,此时队列无法删除
    if (!LOS_ListEmpty(&pstQueueCB->stMemList))
    {
        uwRet = LOS_ERRNO_QUEUE_IN_TSKUSE;
        goto QUEUE_END;
    }

    if ((pstQueueCB->usReadWriteableCnt[OS_QUEUE_WRITE] + pstQueueCB->usReadWriteableCnt[OS_QUEUE_READ]) != pstQueueCB->usQueueLen)
    {
//(6)如果队列的读写不同步,返回错误代码
        uwRet = LOS_ERRNO_QUEUE_IN_TSKWRITE;
        goto QUEUE_END;
    }

    pucQueue = pstQueueCB->pucQueue;
    pstQueueCB->pucQueue = (UINT8 *)NULL;
//(7)将要删除的队列变为未使用状态,添加到消息队列控制块空闲列表中返还给系统
    pstQueueCB->usQueueState = OS_QUEUE_UNUSED;
    LOS_ListAdd(&g_stFreeQueueList, &pstQueueCB->stReadWriteList[OS_QUEUE_WRITE]);
    LOS_IntRestore(uvIntSave);
//(8)释放队列内存
    uwRet = LOS_MemFree(m_aucSysMem0, (VOID *)pucQueue);
    return uwRet;

QUEUE_END:
    LOS_IntRestore(uvIntSave);
    return uwRet;

6.3 消息队列写消息函数

消息队列的消息写入函数有两种,一种是不带复制方式的LOS_QueueWrite,一种是带复制方式的LOS_QueueWriteCopy。不带复制的函数实际上是对带复制的函数进行了封装。

任务或中断服务程序都可以给消息队列写消息,写入的消息复制到队列尾,否则根据定义的阻塞时间进行阻塞。超时了队列还是满的就返回错误。

(1)写入前先创建队列

(2)中断服务程序,必须用非阻塞方式写入,即等待时间为0

(3)初始化LiteOS前无法调用

(4)写入的信息大小不能大于消息节点大小

(5)写入队列节点中的是消息的地址(不带复制的函数)

(5)写入队列节点中的是存储在BufferAdder中的消息(带复制的函数)

6.3.1 不带复制的方式:
LITE_OS_SEC_TEXT UINT32 LOS_QueueWrite(UINT32 uwQueueID,//队列ID
                                       VOID *pBufferAddr, //消息起始地址
                                       UINT32 uwBufferSize, //写入消息的大小
                                       UINT32 uwTimeOut)//等待时间,中断程序中使用时为0
{
    if(pBufferAddr == NULL)
    {
        return LOS_ERRNO_QUEUE_WRITE_PTR_NULL;
    }
    uwBufferSize = sizeof(UINT32*);
    return LOS_QueueWriteCopy(uwQueueID, &pBufferAddr, uwBufferSize, uwTimeOut);
}

6.3.2 带复制的方式:
LITE_OS_SEC_TEXT UINT32 LOS_QueueWriteCopy( UINT32 uwQueueID,//队列ID
                                     VOID * pBufferAddr,//写入消息的起始地址
                                     UINT32 uwBufferSize,//写入消息的大小
                                     UINT32 uwTimeOut )//等待时间
{
    UINT32 uwRet;
    UINT32 uwOperateType;
//对传进来的参数进行检查,如果参数非法,返回错误代码
    uwRet = osQueueWriteParameterCheck(uwQueueID, pBufferAddr, &uwBufferSize, uwTimeOut);
    if(uwRet != LOS_OK)
    {
        return uwRet;
    }
//保存处理的类型,LiteOS采用通用的处理消息队列的方式进行消息处理,见6.4
//对于复制写入的消息,操作方式是写入OS_QUEUE_WRITE,位置是队列尾部OS_QUEUE_TAIL
    uwOperateType = OS_QUEUE_OPERATE_TYPE(OS_QUEUE_WRITE, OS_QUEUE_TAIL);
    return osQueueOperate(uwQueueID, uwOperateType, pBufferAddr, &uwBufferSize, uwTimeOut);
}

6.4 通用的消息队列处理函数
LITE_OS_SEC_TEXT UINT32 osQueueOperate(UINT32 uwQueueID, UINT32 uwOperateType, VOID *pBufferAddr, UINT32 *puwBufferSize, UINT32 uwTimeOut)
{
    QUEUE_CB_S *pstQueueCB;
    LOS_TASK_CB  *pstRunTsk;
    UINTPTR      uvIntSave;
    LOS_TASK_CB  *pstResumedTask;
    UINT32       uwRet = LOS_OK;
//(1)通过函数得到即将处理的操作类型,0代表读,1代表写
    UINT32       uwReadWrite = OS_QUEUE_READ_WRITE_GET(uwOperateType);
//(2)屏蔽中断
    uvIntSave = LOS_IntLock();
//(3)通过队列ID获取队列控制块,并判断队列是否已使用,未使用则返回错误
    pstQueueCB = (QUEUE_CB_S *)GET_QUEUE_HANDLE(uwQueueID);
    if (OS_QUEUE_UNUSED == pstQueueCB->usQueueState)
    {
        uwRet = LOS_ERRNO_QUEUE_NOT_CREATE;
        goto QUEUE_END;

    }
//(4)如果是读消息操作,判断存放消息的地址空间大小能否放的下消息队列的消息,放不下则返回错误
    if(OS_QUEUE_IS_READ(uwOperateType) && (*puwBufferSize < pstQueueCB->usQueueSize - sizeof(UINT32)))
    {
        uwRet = LOS_ERRNO_QUEUE_READ_SIZE_TOO_SMALL;
        goto QUEUE_END;
    }//(5)如果是写入,判断消息大小、消息节点大小,即能否存储要写入的消息
    else if(OS_QUEUE_IS_WRITE(uwOperateType) && (*puwBufferSize > pstQueueCB->usQueueSize - sizeof(UINT32)))
    {
        uwRet = LOS_ERRNO_QUEUE_WRITE_SIZE_TOO_BIG;
        goto QUEUE_END;
    }
//(6)如果当前队列可读的消息个数为0,不能读。写也是一样。
    if (0 == pstQueueCB->usReadWriteableCnt[uwReadWrite])
    {
        if (LOS_NO_WAIT == uwTimeOut)
        {
//(7)不可读写的请胯下,加入未设置阻塞超时,根据是读操作还是写操作返回对应错误代码
            uwRet = OS_QUEUE_IS_READ(uwOperateType) ? LOS_ERRNO_QUEUE_ISEMPTY : LOS_ERRNO_QUEUE_ISFULL;
            goto QUEUE_END;
        }

        if (g_usLosTaskLock)
        {
//(8)如果任务被闭锁,不允许操作消息队列
            uwRet = LOS_ERRNO_QUEUE_PEND_IN_LOCK;
            goto QUEUE_END;
        }
//(9)获取当前任务的任务控制块
        pstRunTsk = (LOS_TASK_CB *)g_stLosTask.pstRunTask;
//(10)根据用户指定的阻塞超时时间等待,把当前任务添加到对应操作队列的阻塞列表中
//写—>写操作阻塞列表,有空闲消息节点时恢复就绪态执行写入操作,超时恢复就绪态
//读—>读操作阻塞列表,、等到其他任务/中断写入消息,当队列有可读消息时恢复就绪态执行操作,超时恢复就绪态
        osTaskWait(&pstQueueCB->stReadWriteList[uwReadWrite], OS_TASK_STATUS_PEND_QUEUE, uwTimeOut);
        LOS_IntRestore(uvIntSave);
//(11)任务切换
        LOS_Schedule();

        uvIntSave = LOS_IntLock();
//(12)判断阻塞解除原因,如果是超时,返回错误代码
        if (pstRunTsk->usTaskStatus & OS_TASK_STATUS_TIMEOUT)
        {
            pstRunTsk->usTaskStatus &= (~OS_TASK_STATUS_TIMEOUT);
            uwRet = LOS_ERRNO_QUEUE_TIMEOUT;
            goto QUEUE_END;
        }
    }
    else
    {
//(13)不是超时解除阻塞,说明消息队列可读写,可读写的消息个数减一
        pstQueueCB->usReadWriteableCnt[uwReadWrite]--;
    }
//(14)调用函数进行对应操作,函数如下所示
    osQueueBufferOperate(pstQueueCB, uwOperateType, pBufferAddr, puwBufferSize);
//(15)如果与当前操作相反的另一个阻塞列表中有任务阻塞,操作完成后恢复任务
    if (!LOS_ListEmpty(&pstQueueCB->stReadWriteList[!uwReadWrite])) /*lint !e514*/
    {
        pstResumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&pstQueueCB->stReadWriteList[!uwReadWrite])); /*lint !e413 !e514*/
//(16)调用函数,唤醒任务
        osTaskWake(pstResumedTask, OS_TASK_STATUS_PEND_QUEUE);
        LOS_IntRestore(uvIntSave);
//(17)进行一次,任务调度
        LOS_Schedule();
        return LOS_OK;
    }
    else
    {
//(18)如果没有任务阻塞与当前操作相反的阻塞列表,与当前操作相反的可用消息个数+1.
//写完后可读消息个数加一,读取完后可写消息个数加一
        pstQueueCB->usReadWriteableCnt[!uwReadWrite]++; /*lint !e514*/
    }

QUEUE_END:
    LOS_IntRestore(uvIntSave);
    return uwRet;
}

osQueueBufferOperate函数源码

LITE_OS_SEC_TEXT static VOID osQueueBufferOperate(QUEUE_CB_S *pstQueueCB, UINT32 uwOperateType, VOID *pBufferAddr, UINT32 *puwBufferSize)
{
    UINT8        *pucQueueNode;
    UINT32       uwMsgDataSize = 0;
    UINT16      usQueuePosion = 0;

    /* get the queue position */
    switch (OS_QUEUE_OPERATE_GET(uwOperateType))
    {
        case OS_QUEUE_READ_HEAD:
            usQueuePosion = pstQueueCB->usQueueHead;
//支持回卷操作,可读或可写指针到达队尾时重置为0开始
            (pstQueueCB->usQueueHead + 1 == pstQueueCB->usQueueLen) ? (pstQueueCB->usQueueHead = 0) : (pstQueueCB->usQueueHead++);
            break;

        case OS_QUEUE_WRITE_HEAD:
            (0 == pstQueueCB->usQueueHead) ? (pstQueueCB->usQueueHead = pstQueueCB->usQueueLen - 1) : (--pstQueueCB->usQueueHead);
//消息队列支持LIFO,将消息队列头部写入消息
            usQueuePosion = pstQueueCB->usQueueHead;
            break;

        case OS_QUEUE_WRITE_TAIL :
            usQueuePosion = pstQueueCB->usQueueTail;
            (pstQueueCB->usQueueTail + 1 == pstQueueCB->usQueueLen) ? (pstQueueCB->usQueueTail = 0) : (pstQueueCB->usQueueTail++);
            break;

        default: //read tail , reserved.
            PRINT_ERR("invalid queue operate type!\n");
            return;
    }

    pucQueueNode = &(pstQueueCB->pucQueue[(usQueuePosion * (pstQueueCB->usQueueSize))]);

    if(OS_QUEUE_IS_READ(uwOperateType))
    {
        memcpy((VOID *)&uwMsgDataSize, (VOID *)(pucQueueNode + pstQueueCB->usQueueSize - sizeof(UINT32)), sizeof(UINT32));
        memcpy((VOID *)pBufferAddr, (VOID *)pucQueueNode, uwMsgDataSize);
        *puwBufferSize = uwMsgDataSize;
    }
    else
    {
        memcpy((VOID *)pucQueueNode, (VOID *)pBufferAddr, *puwBufferSize);
        memcpy((VOID *)(pucQueueNode + pstQueueCB->usQueueSize - sizeof(UINT32)), puwBufferSize, sizeof(UINT32));
    }
}

6.5 消息队列读消息函数

同样的分为带复制方式和不带复制方式的两种函数

(1)读取前要先创建队列,根据队列ID进行读取

(2)队列读取采用的是先进先出模式,先读取存储在队列头部的消息

(3)用户必须定义一个存储地址的变量,假设为r-queue,并把存储消息的地址传递给读取函数,否则发生地址非法错误

(4)中断服务程序中必须用非阻塞,等待时间为0

(5)初始化LiteOS之前无法调用读函数

(6)r-queue变量中存储的是队列节点的地址

(7)LOS_QueueReadCopy和LOS_QueueWriteCopy是一组接口,LOS_QueueRead和LOS_QueueWrite是一组接口,两组接口配套使用。

(8)用户必须在读取消息时指定读取消息的大小,其值不能小于消息节点的大小。

6.5.1 不带复制方式读取函数LOS_QueueRead
LITE_OS_SEC_TEXT UINT32 LOS_QueueRead(UINT32  uwQueueID, //队列ID
                                        VOID *pBufferAddr, //存储获取消息的起始地址
                                        UINT32 uwBufferSize, //读取消息缓冲区的大小
                                        UINT32 uwTimeOut)//等待时间
{
    return LOS_QueueReadCopy(uwQueueID, pBufferAddr, &uwBufferSize, uwTimeOut);
}

6.5.2 带复制方式读取函数LOS_QueueReadCopy
LITE_OS_SEC_TEXT UINT32 LOS_QueueReadCopy(UINT32  uwQueueID,//队列ID
                    VOID *  pBufferAddr,//存储获取消息的起始地址
                    UINT32 * puwBufferSize,//读取消息缓冲区的大小
                    UINT32  uwTimeOut)//等待时间
{
    UINT32 uwRet;
    UINT32 uwOperateType;

    uwRet = osQueueReadParameterCheck(uwQueueID, pBufferAddr, puwBufferSize, uwTimeOut);
    if(uwRet != LOS_OK)
    {
        return uwRet;
    }

    uwOperateType = OS_QUEUE_OPERATE_TYPE(OS_QUEUE_READ, OS_QUEUE_HEAD);
    return osQueueOperate(uwQueueID, uwOperateType, pBufferAddr, puwBufferSize, uwTimeOut);
}

7.消息队列实验main文件

/* LiteOS 头文件 */
#include "los_sys.h"
#include "los_task.ph"
#include "los_queue.h"
/* 板级外设头文件 */
#include "bsp_usart.h"
#include "bsp_led.h"
#include "bsp_key.h"
/* 定义任务句柄 */
UINT32 Receive_Task_Handle;
UINT32 Send_Task_Handle;

/*定义消息队列ID*/
UINT32 Test_Queue_Handle;

/*定义消息队列长度*/
#define TEST_QUEUE_LEN    16
#define TEST_QUEUE_SIZE   16

/*声明全局变量*/
UINT32 send_data1 = 1;
UINT32 send_data2 = 2;

/* 函数声明 */
static UINT32 AppTaskCreate(void);
static UINT32 Creat_Receive_Task(void);
static UINT32 Creat_Send_Task(void);

static void Receive_Task(void);
static void Send_Task(void);
static void BSP_Init(void);



int main(void)
{    
    UINT32 uwRet = LOS_OK;  //定义一个任务创建的返回值,默认为创建成功
    
    /* 板载相关初始化 */
  BSP_Init();
    
    printf("按下KEY1或者KEY2写入队列消息\r\n");
    printf("Receive_Task 任务读取到消息在串口回显\r\n");
    /* LiteOS 内核初始化 */
    uwRet = LOS_KernelInit();
    
  if (uwRet != LOS_OK)
  {
        printf("LiteOS 核心初始化失败!失败代码0x%X\n",uwRet);
        return LOS_NOK;
  }

    uwRet = AppTaskCreate();
    if (uwRet != LOS_OK)
  {
        printf("AppTaskCreate创建任务失败!失败代码0x%X\n",uwRet);
        return LOS_NOK;
  }

  /* 开启LiteOS任务调度 */
  LOS_Start();
    
    //正常情况下不会执行到这里
    while(1);
    
}

static UINT32 AppTaskCreate(void)
{
    /* 定义一个返回类型变量,初始化为LOS_OK */
    UINT32 uwRet = LOS_OK;
    
    /*创建一个测试队列*/
    uwRet = LOS_QueueCreate("Test_Queue",TEST_QUEUE_LEN,&Test_Queue_Handle,0,TEST_QUEUE_SIZE);
    if(uwRet!=LOS_OK)
    {
            printf("Test_Queue队列创建失败!失败代码0x%X\n",uwRet);
            return uwRet;
    }
    
    
    
    
    uwRet = Creat_Receive_Task();
  if (uwRet != LOS_OK)
  {
        printf("Receive_Task任务创建失败!失败代码0x%X\n",uwRet);
        return uwRet;
  }
    
    uwRet = Creat_Send_Task();
  if (uwRet != LOS_OK)
  {
        printf("Send_Task任务创建失败!失败代码0x%X\n",uwRet);
        return uwRet;
  }
    return LOS_OK;
}



static UINT32 Creat_Receive_Task()
{
    //定义一个创建任务的返回类型,初始化为创建成功的返回值
    UINT32 uwRet = LOS_OK;            
    
    //定义一个用于创建任务的参数结构体
    TSK_INIT_PARAM_S task_init_param;    

    task_init_param.usTaskPrio = 5;    /* 任务优先级,数值越小,优先级越高 */
    task_init_param.pcName = "Receive_Task";/* 任务名 */
    task_init_param.pfnTaskEntry = (TSK_ENTRY_FUNC)Receive_Task;/* 任务函数入口 */
    task_init_param.uwStackSize = 1024;        /* 堆栈大小 */

    uwRet = LOS_TaskCreate(&Receive_Task_Handle, &task_init_param);/* 创建任务 */
    return uwRet;
}


static UINT32 Creat_Send_Task()
{
    // 定义一个创建任务的返回类型,初始化为创建成功的返回值
    UINT32 uwRet = LOS_OK;                
    TSK_INIT_PARAM_S task_init_param;

    task_init_param.usTaskPrio = 4;    /* 任务优先级,数值越小,优先级越高 */
    task_init_param.pcName = "Send_Task";    /* 任务名*/
    task_init_param.pfnTaskEntry = (TSK_ENTRY_FUNC)Send_Task;/* 任务函数入口 */
    task_init_param.uwStackSize = 1024;    /* 堆栈大小 */
    
    uwRet = LOS_TaskCreate(&Send_Task_Handle, &task_init_param);/* 创建任务 */

    return uwRet;
}



static void Receive_Task(void)
{
    /*定义一个返回类型变量,初始化LOS_OK*/
    UINT32 uwRet = LOS_OK;
    UINT32 r_queue;
    UINT32 buffsize =16;
  /* 任务都是一个无限循环,不能返回 */
    while(1)
    {
        uwRet = LOS_QueueRead(Test_Queue_Handle,&r_queue,buffsize,LOS_WAIT_FOREVER);
        if(LOS_OK == uwRet){
            printf("本次读取到的消息是%d\n",*(UINT32 *) r_queue);
        }else {
            printf("消息读取出错,错误代码0x%X\n",uwRet);
        }
    }
}

static void Send_Task(void)
{
    UINT32 uwRet = LOS_OK;
  /* 任务都是一个无限循环,不能返回 */
    while(1)
    {
        
   if(Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN)==KEY_ON){
            
            uwRet = LOS_QueueWrite(Test_Queue_Handle,&send_data1,sizeof(send_data1),0);
            if(LOS_OK != uwRet){
                    printf("消息不能写入到消息队列!错误代码0x%X\r\n",uwRet);
            }
     }
            else if(Key_Scan(KEY2_GPIO_PORT,KEY2_GPIO_PIN)==KEY_ON){
            uwRet = LOS_QueueWrite(Test_Queue_Handle,&send_data2,sizeof(send_data2),0);
            if(LOS_OK != uwRet){
                    printf("消息不能写入到消息队列!错误代码0x%X\r\n",uwRet);
            }
            
     
     }
            LOS_TaskDelay(20);
    }
}

/*******************************************************************
  * @ 函数名  : BSP_Init
  * @ 功能说明: 板级外设初始化,所有板子上的初始化均可放在这个函数里面
  * @ 参数    :   
  * @ 返回值  : 无
  ******************************************************************/
static void BSP_Init(void)
{
    /*
     * STM32中断优先级分组为4,即4bit都用来表示抢占优先级,范围为:0~15
     * 优先级分组只需要分组一次即可,以后如果有其他的任务需要用到中断,
     * 都统一用这个优先级分组,千万不要再分组,切忌。
     */
    NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );
    
    /* LED 初始化 */
    LED_GPIO_Config();

    /* 串口初始化    */
    USART_Config();
    /* KEY初始化 */
    Key_GPIO_Config();
}


/******************************END OF FILE*******************/

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值