一.互斥的引入
 在FreeRTOS中,互斥(Mutex)是一种用于保护共享资源的机制。互斥锁可以确保同一时间只有一个任务能够访问共享资源,从而避免了竞态条件和数据不一致的问题。
FreeRTOS中互斥的引入方法:
-  创建互斥锁: - 使用 xSemaphoreCreateMutex()函数创建一个互斥锁。
- 该函数返回一个互斥锁句柄,可以通过该句柄引用互斥锁。
 
- 使用 
-  获取互斥锁: - 任务通过调用 xSemaphoreTake()函数来获取互斥锁。
- 如果互斥锁当前没有被其他任务占用,这个任务将获取到互斥锁,并可以进入临界区(访问共享资源的代码块)。
- 如果互斥锁已经被其他任务占用,则当前任务将被阻塞,直到互斥锁被释放。
 
- 任务通过调用 
-  释放互斥锁: - 任务在完成对共享资源的访问后,通过调用 xSemaphoreGive()函数来释放互斥锁。
- 当互斥锁被释放后,其他等待获取互斥锁的任务就可以获取到它,并继续执行临界区的代码。
 
- 任务在完成对共享资源的访问后,通过调用 
需要注意的是,获取互斥锁是一种阻塞操作,即如果互斥锁当前不可用,任务将被阻塞,直到互斥锁可用。互斥锁的获取和释放应该成对出现,确保正确的同步和保护共享资源。
互斥锁的应用可确保共享资源的访问是原子性的,避免了多个任务同时访问共享资源导致的数据不一致和竞争问题。
请注意,互斥锁的使用要合理,并避免死锁和优先级翻转等问题,这在设计多任务系统时需要特别注意。
二.队列
在FreeRTOS中,队列(Queue)是一种常用的通信机制,用于在任务之间传递数据。队列提供了一种安全、可靠的方式,使任务能够以先进先出(FIFO)的顺序接收和发送数据。
以下是FreeRTOS中队列的一些特点和使用方法:
-  创建队列: - 使用 xQueueCreate()函数创建一个队列。
- 需要指定队列的长度和每个队列元素的大小。
 
- 使用 
-  发送数据到队列: - 使用 xQueueSend()或xQueueSendFromISR()函数将数据发送到队列。
- 数据将会被复制到队列中,原始数据不会受到影响。
- 如果队列已满,任务可以等待一段时间或放弃发送,具体取决于函数的阻塞方式。
 
- 使用 
-  接收数据从队列: - 使用 xQueueReceive()或xQueueReceiveFromISR()函数从队列中接收数据。
- 如果队列为空,任务可以等待一段时间或放弃接收,具体取决于函数的阻塞方式。
- 接收到的数据将被复制到接收方提供的变量中。
 
- 使用 
-  检查队列状态: - 使用 uxQueueMessagesWaiting()函数可以获取当前队列中待处理的消息数目。
- 使用 uxQueueSpacesAvailable()函数可以获取队列中剩余的空闲空间。
 
- 使用 
队列提供了一种灵活的方式来实现任务之间的数据共享和通信。它可以在不同的优先级任务之间传递消息,以及在任务和中断服务程序(ISR)之间传递消息。
需要注意的是,队列的长度和每个队列元素的大小需要根据具体的应用场景来选择。队列也可以用来传递指针,使得更大的数据结构可以在任务之间共享。
Queue服务API函数具有不同的变体,可以根据应用程序的需求进行选择和使用。同时,队列还可以与其他FreeRTOS组件(如任务、定时器和信号量等)一起使用,以构建复杂的嵌入式系统。
![![2024-02-21T13:56:09.png][1]](https://img-blog.csdnimg.cn/direct/ca72f7cd48164c209a76adab300fa7c1.png)
使用场景
下情况下特别适用:
-  任务间数据交流:当不同任务之间需要传递数据时,队列是一种安全可靠的机制。任务可以通过发送消息到队列来向其他任务传递数据,而不需要直接访问对方的数据结构。 
-  任务和中断服务程序(ISR)之间的通信:中断服务程序通常无法直接与任务通信,因为它们在执行时中断了任务的上下文。通过使用队列,中断服务程序可以将数据发送到队列,任务可以在适当的时候从队列中接收并处理数据。 
-  流量控制:队列可以用于控制任务之间的数据流量。发送任务可以根据接收任务处理数据的速度来控制发送频率,避免数据的积压或丢失。 
-  事件通知:队列还可以用于通知任务发生特定事件。当任务完成某项任务或达到某个条件时,它可以向队列发送一个特殊的消息,其他任务可以通过接收这个消息来作出相应的响应。 
-  缓冲区:队列可以用作缓冲区,以平衡不同速度的生产者和消费者。生产者可以将数据放入队列,而消费者可以按照自己的速度从队列中取出数据。 
需要根据具体的应用场景来判断是否需使用队列。如果任务之间需要传递数据、需要控制数据流量或需要通知事件,那么使用队列是一个不错的选择。队列提供了一种安全、可靠的机制来实现任务之间的数据共享和通信。
xQueueSend函数
关中断,发数据,开中断
如果你想在中断状态下直接写入数据到队列,并且在写入完成后恢复中断状态,你可以按照以下步骤进行操作:
-  在任务初始化时,通过 xQueueCreate()函数创建一个队列,并将其句柄保存在适当的变量中。
-  在中断服务程序中,可以使用 xQueueSend()函数来向队列中发送数据。在发送数据前,需要先禁用中断,以确保写入数据的过程不会被打断。示例如下: // 关闭中断 portDISABLE_INTERRUPTS();// 向队列发送数据 xQueueSend(xQueueHandle, &data, portMAX_DELAY);// 恢复中断 portENABLE_INTERRUPTS();在发送数据到队列后,可以根据 xQueueSend()函数的返回值(是否成功发送)来执行相应的错误处理或日志记录。
需要注意的是,在中断中直接调用 xQueueSend() 函数时,需要确保队列的长度足够大,以避免在中断期间发生队列溢出的情况。另外,虽然中断服务程序的执行时间应该尽可能地短,但在某些情况下,如果队列发送操作无法立即完成,例如队列已满时,则可以使用 portMAX_DELAY 参数来阻塞等待队列可用。
请注意,使用这种方法需要特别小心,并确保在此期间没有其他任务会访问或更改队列,以免产生竞争条件和数据一致性问题。此外,如果有其他中断启用,并且具有更高优先级的中断可能发生时,建议使用 xQueueSendFromISR() 函数来发送数据,以便安全地在中断上下文中操作队列。