物联网下的RTOS开发(三)——队列的进阶

队列的进阶

 

一、队列、消息队列

队列是什么,对于程序员都不会陌生,在单片机开发的时候,也会有接触。比如串口,有些MCU的串口为了高效自带FIFO功能。队列简单易用,在物联网下基于RTOS的开发中更是显神通,称为消息队列。

消息队列在FreeRTOS下所有的通信与同步机制都是基于队列实现的。用法和创建任务类似,独立于任务,也是RTOS下核心的一个组件。主要有几个特性:

1.缓冲数据:和普通队列一样

关注溢出,RTOS下数据的大小和队列的深度(个数)应该是已知的。不允许装入超出创建大小范围的数据。比如创建的时候队列大小为128个字节,个数为3。而实际装入的数据超过128,那么就给引入hardfault或者堆栈异常等问题。

2.多任务安全调用

关注安全,系统允许用户多任务对一个队列写入内容,至于队列本身的安全由系统保证。

3.阻塞

读空或写入满的时候会阻塞,可以用来把任务挂起,这个功能和消息队列的用法是一样的。

4.地址传输

如果需要传输的数据比较大。比如超过512/1024个字节,且经常要传输的数据。可以考虑传输地址的操作。FreeRTOS下的头文件中已经给出了示例,如下:

struct AMessage

 {

     char ucMessageID;

     char ucData[ 20 ];

 } xMessage;

QueueHandle_t xQueue;

 

// Task to create a queue and post a value.

void vATask( void *pvParameters )

{

 struct AMessage *pxMessage;

 

// Create a queue capable of containing 10 pointers to AMessage structures.

// These should be passed by pointer as they contain a lot of data.

xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );

if( xQueue == 0 )

{

        // Failed to create the queue.

}

 

// ...

 

// Send a pointer to a struct AMessage object.  Don't block if the

// queue is already full.

pxMessage = & xMessage;

xQueueSend( xQueue, ( void * ) &pxMessage, ( TickType_t ) 0 );

 

// ... Rest of task code.

 }

 

 // Task to receive from the queue.

 void vADifferentTask( void *pvParameters )

 {

 struct AMessage *pxRxedMessage;

 

if( xQueue != 0 )

{

        // Receive a message on the created queue.  Block for 10 ticks if a

        // message is not immediately available.

        if( xQueueReceive( xQueue, &( pxRxedMessage ), ( TickType_t ) 10 ) )

        {

               // pcRxedMessage now points to the struct AMessage variable posted

               // by vATask.

        }

}

 

// ... Rest of task code.

 }

      

二、物联网场景

       为了方便区分以下列出一些使用场景:

1.上行入队,统一处理

IOT场景下往往和服务器保持长连接。长连接除了要负责心跳外,还有来自不同传感器的数据,串口的数据上报等。心跳和传感器,串口数据可能来不同的任务,中断等。那么这些数据都通过在不同的任务下发给一个队列。统一由一个任务取出队列数据,进行上行。

这样做有几个好处:不会存在入队的临界问题。统一上行系统稳定可靠,可重用。多任务调用网络接口不同的传输形式往往要求不同。数据是否上行可以标记。坏处就是效率相对低。

 

2.普通队列的进阶

普通队列的最大的问题是不可以被多个任务写,当然读也是不行的(应该没人这么干吧)。参考单字节入队的形式改为有限个动态内存分配的入队模式,出队的时候释放内存。如果能够保证业务允许在消费者模型的种场景中实现,这种模型可以大大提高任务调度的效率。

 

三、模型设计

1.    根据以上设计模型给出如下

    

//创建一个处理消息队列任务
void Task_mian_upload()
{
	while(1)
	{
		// 等待消息队列
		if( xQueueReceive( xQueue, &( pxRxedMessage ), ( TickType_t ) 10 ) )	
        {
    		// do something.
		    send(…);	//发送来自pxRxedMessage的数据到服务器
        }
        …
    }
}


void Task_mian_upload()
{
    while(1)
    {
        // 等待消息队列
        if( xQueueReceive( xQueue, &( pxRxedMessage ), ( TickType_t ) 10 ) ) 
        {
            // do something.
            send(…); //发送来自pxRxedMessage的数据到服务器
        }
        …
    }
}


void Take_1_send_Q()
{
    while(1)
    {
        …
        if(true == check_temp())     // 定时检查温度
        {
            // 发送温度值到网络
            xQueueSend (xQueue ,temp);     // 发送消息队列
        }
        …
    }
}


// 中断中触发事件
void _ISR1()
{
    //发送事件类型消息队列
    xQueueSendFromISR(xQueue,…);
}

 

以上第一个任务集中处理来自其他任务或者中断的消息队列,其他任务会根据任务或者事件的触发情况发送数据到消息队列中。第一个任务将接收到的消息队列内处理后,发送到网络中。

你可能感兴趣的:(RTOS,物联网,设计模型)