FreeRTOS入门
本文最后更新于309 天前,其中的信息可能已经过时,如有错误请发送邮件到y.wt@foxmail.com

同步互斥与通信

队列

什么是队列

  • 队列的内部是一个结构体, 主要由一个buffer指针 和两个链表(等待写入数据和等待读出数据链表)组成
  • 队列的实质是一个环形数据缓冲区

队列特性

1、队列的阻塞访问,这也是队列能够实现任务同步与互斥的主要原因

当一个任务写队列时,当队伍满了,该任务也可进入阻塞状态还可以指定阻塞的时间。如果队列有空间了,则该阻塞的任务会变为就绪态。如果一直都没有空间,则时间到之后它也会进入就绪态。既然写队列的任务个数没有限制,那么当多个任务写”满队列”时,这些任务都会进入阻塞状态:有多个任务在等待同一个队列的空间。当队列中有空间时,哪个任务会进入就绪态?

  • 优先级最高的任务
  • 如果大家的优先级相同,那等待时间最久的任务会进入就绪态
2、分辨数据源

将数据打包为一个结构体,存放发送方的名称和数据。

typedef struct {
ID_t eDataID;
int32_t lDataValue;
}Data_t;

不同的发送任务,先构造好结构体,填入自己的 eDataID ,再写队列;接收任务读出数据后,根据eDataID 就可以知道数据来源了。

3、传输大块数据

把大数据的结构体(大块数据)的地址写入队列,对方从队列得到这个地址,使用地址去访问那1000字节的数据。

使用地址来间接传输数据时,这些数据放在RAM里,对于这块RAM,要保证这几点:

  • RAM的所有者、操作者,必须清晰明了这块内存,就被称为”共享内存”。要确保不能同时修改RAM。比如,在写队列之前只有由发送者修改这块RAM,在读队列之后只能由接收者访问这块RAM。
  • RAM要保持可用这块RAM应该是全局变量,或者是动态分配的内存。对于动然分配的内存,要确保它不能提前释放:要等到接收者用完后再释放。另外,不能是局部变量。

队列函数及参数

创建队列

QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength,
                            UBaseType_t uxItemSize
);

删除队列

删除队列的函数为 vQueueDelete() ,只能删除使用动态方法创建的队列,它会释放内存。原型如下:

void vQueueDelete( QueueHandle_t xQueue );

写入队列

可以把数据写到队列头部BaseType_t xQueueSendToFront(),此时数据会插入到队列的头部,将被最先读出来,并且不会覆盖原来的数据。

也可以写到尾部

/* 等同于xQueueSendToBack
* 往队列尾部写入数据,如果没有空间,阻塞时间为xTicksToWait
*/
BaseType_t xQueueSend(QueueHandle_t xQueue,
                      const void *pvItemToQueue,
                      TickType_t xTicksToWait
);
/*
* 往队列尾部写入数据,如果没有空间,阻塞时间为xTicksToWait
*/

读取队列

BaseType_t xQueueReceive( QueueHandle_t xQueue,
                          void * const pvBuffer,
                          TickType_t xTicksToWait
 );

在任务中创建队列

/* 队列句柄, 创建队列时会设置这个变量 */
QueueHandle_t xQueue;
int main( void )
{
prvSetupHardware();
/* 创建队列: 长度为5,数据大小为4字节(存放一个整数) */
xQueue = xQueueCreate( 5, sizeof( int32_t ) );
if( xQueue != NULL )
{
/* 创建2个任务用于写队列, 传入的参数分别是100、200
* 任务函数会连续执行,向队列发送数值100、200
* 优先级为1
*/
xTaskCreate( vSenderTask, "Sender1", 1000, ( void * ) 100, 1, NULL );
xTaskCreate( vSenderTask, "Sender2", 1000, ( void * ) 200, 1, NULL );
/* 创建1个任务用于读队列
* 优先级为2, 高于上面的两个任务
* 这意味着队列一有数据就会被读走
*/
xTaskCreate( vReceiverTask, "Receiver", 1000, NULL, 2, NULL );
/* 启动调度器 */
vTaskStartScheduler();
}
else
{
/* 无法创建队列 */
}
/* 如果程序运行到了这里就表示出错了, 一般是内存不足 */
return 0;
}

在任务中写入队列

static void vSenderTask( void *pvParameters )
{
int32_t lValueToSend;
BaseType_t xStatus;
/* 我们会使用这个函数创建2个任务
* 这些任务的pvParameters不一样
*/
lValueToSend = ( int32_t ) pvParameters;
/* 无限循环 */
for( ;; )
{
/* 写队列
* xQueue: 写哪个队列
* &lValueToSend: 写什么数据? 传入数据的地址, 会从这个地址把数据复制进队列
* 0: 不阻塞, 如果队列满的话, 写入失败, 立刻返回
*/
xStatus = xQueueSendToBack( xQueue, &lValueToSend, 0 );
if( xStatus != pdPASS )
{
printf( "Could not send to the queue.\r\n" );
}
}
}

在任务中读取队列

static void vReceiverTask( void *pvParameters )
{
/* 读取队列时, 用这个变量来存放数据 */
int32_t lReceivedValue;
BaseType_t xStatus;
const TickType_t xTicksToWait = pdMS_TO_TICKS( 100UL );
/* 无限循环 */
for( ;; )
{
/* 读队列
* xQueue: 读哪个队列
* &lReceivedValue: 读到的数据复制到这个地址
* xTicksToWait: 如果队列为空, 阻塞一会
*/
xStatus = xQueueReceive( xQueue, &lReceivedValue, xTicksToWait );
if( xStatus == pdPASS )
{
/* 读到了数据 */
printf( "Received = %d\r\n", lReceivedValue );
}
else
{
/* 没读到数据 */
printf( "Could not receive from the queue.\r\n" );
}
}
}

队列的使用示例

利用队列实现任务同步与任务互斥

同步

当任务1开始计数时,任务2进入阻塞状态,不参与任务调度,直到计数完成,任务1向队列写入数据同时唤醒任务2读取队列数据,完成通信过程以节约CPU资源

互斥

以串口通信资源的分配为例,两个任务不能同时占用串口资源。通过队列特性构建Lock函数,当队列中有数据时可以通过调用接收信息的函数获得使用权,调用发送信息函数释放使用权。

主函数中

队列集使用示例

队列集(queue set)也是队列,它里面存放的是各个队列(A.B.C)的handle -即队列的队列

  • 当数据写入队列A一次,同时也会写入队列集一次;写入队列A N次,就会写入队列集N次。
  • 反过来,读队列集一次,得到了队列A,也只应该读队列A一次
使用队列集首先要先在配置文件FreeRTOSConfig.h中添加 #define configUSE_QUEUE_SETS 1

1、声明队列handle

2、主函数中创建任务及队列集(queue set)

3、在两个不同任务中分别向队列写入数据。任务1向队列1持续发送变量自增的数据,任务2向队列2持续发送变量自减的数据。

4、从队列集中找到正在传送数据的队列并返回其handle,接收该队列中的数据

打印出通过队列集接收的数据,其中正数为队列1中的数据,负数为队列2中的数据

信号量

与队列的对比

信号量不能用来传输数据

信号量函数

使用方法

文章作者:Walter
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇