入门RTOS第十篇(队列传输大块数据)

FreeRTOS的队列使用拷贝传输,也就是要传输uint32_t时,把4字节的数据拷贝进队列;要传输一个8字节的结构体时,把8字节的数据拷贝进队列。如果要传输1000字节的结构体呢?写队列时拷贝1000字节,读队列时再拷贝1000字节?不建议这么做,影响效率!
这时候,我们要传输的是这个巨大结构体的地址:把它的地址写入队列,对方从队列得到这个地址,使用地址去访问那1000字节的数据。
使用地址来间接传输数据时,这些数据放在RAM里,对于这块RAM,要保证这几点:
RAM的所有者、操作者,必须清晰明了这块内存,就被称为"共享内存"。要确保不能同时修改RAM。比如,在写队列之前只有由发送者修改这块RAM,在读队列之后只能由接收者访问这块RAM。RAM要保持可用这块RAM应该是全局变量,或者是动态分配的内存。对于动然分配的内存,要确保它不能提前释放:要等到接收者用完后再释放。另外,不能是局部变量。创建一个队列,然后创建1个发送任务、1个接收任务:
创建的队列:长度为1,用来传输"char *"指针
发送任务优先级为1,在字符数组中写好数据后,把它的地址写入队列
接收任务优先级为2,读队列得到"char *"值,把它打印出来
这个程序故意设置接收任务的优先级更高,在它访问数组的过程中,接收任务无法执行、无法写这个数组。
main函数中创建了队列、创建了发送任务、接收任务,代码如下:

/* 定义一个字符数组 */
static char pcBuffer[100];
/* vSenderTask被用来创建2个任务,用于写队列
* vReceiverTask被用来创建1个任务,用于读队列
*/
static void vSenderTask( void *pvParameters );
static void vReceiverTask( void *pvParameters );
/*-----------------------------------------------------------*/
/* 队列句柄, 创建队列时会设置这个变量 */
QueueHandle_t xQueue;
int main( void )
{
    prvSetupHardware();
    /* 创建队列: 长度为1,数据大小为4字节(存放一个char指针) */
    xQueue = xQueueCreate( 1, sizeof(char *) );
 
    发送任务的函数中,现在全局大数组pcBuffer中构造数据,然后把它的地址写入队列,代码如下:
    if( xQueue != NULL )
       {
            /* 创建1个任务用于写队列
            * 任务函数会连续执行,构造buffer数据,把buffer地址写入队列
            * 优先级为1
            */
            xTaskCreate( vSenderTask, "Sender", 1000, NULL, 1, NULL );
            /* 创建1个任务用于读队列
            * 优先级为2, 高于上面的两个任务
            * 这意味着读队列得到buffer地址后,本任务使用buffer时不会被打断
            */
            xTaskCreate( vReceiverTask, "Receiver", 1000, NULL, 2, NULL );
            /* 启动调度器 */
            vTaskStartScheduler();
        }
   else
      {
            /* 无法创建队列 */
      }
            /* 如果程序运行到了这里就表示出错了, 一般是内存不足 */
   return 0;
}

发送任务的函数中,现在全局大数组pcBuffer中构造数据,然后把它的地址写入队列,代码如下:

static void vSenderTask( void *pvParameters )
{
    BaseType_t xStatus;
    static int cnt = 0;
    char *buffer;
    /* 无限循环 */
    for( ;; )
    {
        sprintf(pcBuffer, "www.100ask.net Msg %d\r\n", cnt++);
        buffer = pcBuffer; // buffer变量等于数组的地址, 下面要把这个地址写入队列
        /* 写队列
        * xQueue: 写哪个队列
        * pvParameters: 写什么数据? 传入数据的地址, 会从这个地址把数据复制进队列
        * 0: 如果队列满的话, 即刻返回
        */
        xStatus = xQueueSendToBack( xQueue, &buffer, 0 ); /* 只需要写入4字节, 无需
        写入整个buffer */
        if( xStatus != pdPASS )
        {
            printf( "Could not send to the queue.\r\n" );
        }
    }
}

接收任务的函数中,读取队列、得到buffer的地址、打印,代码如下;

static void vReceiverTask( void *pvParameters )
{
    /* 读取队列时, 用这个变量来存放数据 */
    char *buffer;
    const TickType_t xTicksToWait = pdMS_TO_TICKS( 100UL );
    BaseType_t xStatus;
    /* 无限循环 */
    for( ;; )
    {
        /* 读队列
        * xQueue: 读哪个队列
        * &xReceivedStructure: 读到的数据复制到这个地址
        * xTicksToWait: 没有数据就阻塞一会
        */
        xStatus = xQueueReceive( xQueue, &buffer, xTicksToWait); /* 得到buffer地
        址,只是4字节 */
        if( xStatus == pdPASS )
        {
            /* 读到了数据 */
            printf("Get: %s", buffer);
        }
        else
        {
            /* 没读到数据 */
            printf( "Could not receive from the queue.\r\n" );
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

No Bugs ToDay

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值