从多个来源接收数据
在FREERTOS操作系统中,任务从多个数据源获取数据是一件很常见的事,但是,任务在处理数据时需要知道数据来自于哪里,这样才能决定如何处理该数据。为了解决这个问题,一个简单的方法是通过创建一个包含数据来源与数据本身的结构体,将该结构体存到队列中,则读任务即可知道数据的来源,其原理框图如下所示:
其代码示例如下
/* Define an enumerated type used to identify the source of the data. */
typedef enum
{
eSender1,
eSender2
} DataSource_t;
/* Define the structure type that will be passed on the queue. */
typedef struct
{
uint8_t ucValue;
DataSource_t eDataSource;
} Data_t;
/* Declare two variables of type Data_t that will be passed on the queue. */
static const Data_t xStructsToSend[ 2 ] =
{
{
100, eSender1 }, /* Used by Sender1. */
{
200, eSender2 } /* Used by Sender2. */
};
关于大量或可变大小数据的队列
当需要存储在队列中的数据量很大时,将数据的指针放在队列中相比于将数据复制进队列有着更多的优点。
但是需要注意一下几点
1,使用队列指针的任务必须明确,当通过指针来共享一个数据时,一定要保证,不能同时更改数据,或执行导致内存数据无效化或不一致的指令。理想情况下,当队列中没有指针时,应只允许发送数据的任务,当队列中存在指针时,只允许接收队列数据的任务。
2,数据指针指向的内存一定要为有效内存。
使用队列发送不同类型与长度的数据
之前展示了队列存储的两种主要方式,结构体,或指针,如果将二者混合起来即可使得任务使用一个队列从不同信息源接收任一数据类型。下面以FREERTOS中的TCP/IP为例。
TCP/IP栈在任务运行中需要从不同数据源中获取不同类型事件。不同事件有着不同的数据类型与数据长度,在TCP/IP任务外的所有事件都通过结构体IPStackEvent_t来表示,并通过队列传给TCP/IP任务。其结构体类型如下所示:
/* A subset of the enumerated types used in the TCP/IP stack to identify events. */
typedef enum
{
eNetworkDownEvent = 0, /* The network interface has been lost, or needs (re)connecting. */
eNetworkRxEvent, /* A packet has been received from the network. */
eTCPAcceptEvent, /* FreeRTOS_accept() called to accept or wait for a new client. */
/* Other event types appear here but are not shown in this listing. */
} eIPEvent_t;
/* The structure that describes events, and is sent on a queue to the TCP/IP task. */
typedef struct IP_TASK_COMMANDS
{
/* An enumerated type that identifies the event. See the eIPEvent_t definition above. */
eIPEvent_t eEventType;
/* A generic pointer that can hold a value, or point to a buffer. */
void *pvData;
} IPStackEvent_t;
从多个队列中获取数据
队列集合允许任务在不用轮询所有队列的情况下从多个队列中获取数据,采用队列集合方式从多个数据源获取数据相比于单一队列中获取数据更加低效率。所以,除非在不得已情况下,一般不使用队列集合。
使用队列集合的步骤:
1,创建队列集合
2,将队列添加到队列集合。
3,读队列集合来了解队列集合中哪个队列含有数据:当一个集合中的队列接收到了数据,则这个队列的句柄将会被放置到队列集合中,当任务