FreeRTOS — 消息队列

2023-05-16

以下内容转载自安富莱电子:http://forum.armfly.com/forum.php

FreeRTOS 的一个重要的通信机制----消息队列,消息队列在实际项目中应用较多。

1、消息队列

 1.1 消息队列的概念及其作用

  消息队列就是通过 RTOS 内核提供的服务,任务或中断服务子程序可以将一个消息(注意,FreeRTOS消息队列传递的是实际数据,并不是数据地址,RTX,uCOS-II 和 uCOS-III 是传递的地址)放入到队列。同样,一个或者多个任务可以通过 RTOS 内核服务从队列中得到消息。通常,先进入消息队列的消息先传给任务,也就是说,任务先得到的是最先进入到消息队列的消息,即先进先出的原则(FIFO),FreeRTOS的消息队列支持 FIFO 和 LIFO 两种数据存取方式。

  也许有不理解的初学者会问采用消息队列多麻烦,搞个全局数组不是更简单,其实不然。在裸机编程时,使用全局数组的确比较方便,但是在加上 RTOS 后就是另一种情况了。相比消息队列,使用全局数组主要有如下四个问题:

 使用消息队列可以让 RTOS 内核有效地管理任务,而全局数组是无法做到的,任务的超时等机制需要用户自己去实现。
 使用了全局数组就要防止多任务的访问冲突,而使用消息队列则处理好了这个问题,用户无需担心。
 使用消息队列可以有效地解决中断服务程序与任务之间消息传递的问题。
 FIFO 机制更有利于数据的处理。

 1.2 FreeRTOS 任务间消息队列的实现  

  任务间消息队列的实现是指各个任务之间使用消息队列实现任务间的通信。下面我们通过如下的框图来说明一下 FreeRTOS 消息队列的实现,让大家有一个形象的认识。

运行条件:
 创建消息队列,可以存放 10 个消息。
 创建 2 个任务 Task1 和 Task2,任务 Task1 向消息队列放数据,任务 Task2 从消息队列取数据。
 FreeRTOS 的消息存取采用 FIFO 方式。 

运行过程主要有以下两种情况:
 任务 Task1 向消息队列放数据,任务 Task2 从消息队列取数据,如果放数据的速度快于取数据的速度,那么会出现消息队列存放满的情况,FreeRTOS 的消息存放函数 xQueueSend 支持超时等待,用户可以设置超时等待,直到有空间可以存放消息或者设置的超时时间溢出。
 任务 Task1 向消息队列放数据,任务 Task2 从消息队列取数据,如果放数据的速度慢于取数据的速度,那么会出现消息队列为空的情况,FreeRTOS 的消息获取函数 xQueueReceive 支持超时等待,用户可以设置超时等待,直到消息队列中有消息或者设置的超时时间溢出。

  上面就是一个简单的 FreeRTOS 任务间消息队列通信过程,FIFO 方式数据存取过程的动态演示看官方地址:点击这里里面的 GIF 图片。

 1.3 FreeRTOS 中断方式消息队列的实现

  FreeRTOS 中断方式消息队列的实现是指中断函数和 FreeRTOS 任务之间使用消息队列。下面我们通过如下的框图来说明一下 FreeRTOS 消息队列的实现,让大家有一个形象的认识。

运行条件:

 创建消息队列,可以存放 10 个消息。

 创建 1 个任务 Task1 和一个串口接收中断。
 FreeRTOS 的消息存取采用 FIFO 方式。

运行过程主要有以下两种情况:
 中断服务程序向消息队列放数据,任务 Task1 从消息队列取数据,如果放数据的速度快于取数据的速度,那么会出现消息队列存放满的情况。由于中断服务程序里面的消息队列发送函数xQueueSendFromISR 不支持超时设置,所以发送前要通过函数 xQueueIsQueueFullFromISR 检测消息队列是否满。
 中断服务程序向消息队列放数据,任务 Task1 从消息队列取数据,如果放数据的速度慢于取数据的速度,那么会出现消息队列存为空的情况。在 FreeRTOS 的任务中可以通过函数 xQueueReceive 获取消息,因为此函数可以设置超时等待,直到消息队列中有消息存放或者设置的超时时间溢出。

  上面就是一个简单的 FreeRTOS 中断方式消息队列通信过程。实际应用中,中断方式的消息机制要注意以下四个问题:

 中断函数的执行时间越短越好,防止其它低于这个中断优先级的异常不能得到及时响应。
 实际应用中,建议不要在中断中实现消息处理,用户可以在中断服务程序里面发送消息通知任务,在任务中实现消息处理,这样可以有效地保证中断服务程序的实时响应。同时此任务也需要设置为高优先级,以便退出中断函数后任务可以得到及时执行。
 中断服务程序中一定要调用专用于中断的消息队列函数,即以 FromISR 结尾的函数
 在操作系统中实现中断服务程序与裸机编程的区别。
  如果 FreeRTOS 工程的中断函数中没有调用 FreeRTOS 的消息队列 API 函数,与裸机编程是一样的。
  如果 FreeRTOS 工程的中断函数中调用了 FreeRTOS 的消息队列的 API 函数,退出的时候要检测是否有高优先级任务就绪,如果有就绪的,需要在退出中断后进行任务切换,这点与裸机编程稍有区别,详见 实验例程说明(中断方式):
  另外强烈推荐用户将 Cortex-M3 内核的 STM32F103 和 Cortex-M4 内核的 STM32F407,F429的 NVIC 优先级分组设置为 4,即:NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);这样中断优先级的管理将非常方便。
  用户要在 FreeRTOS 多任务开启前就设置好优先级分组,一旦设置好切记不可再修改。

2、消息队列API函数

  使用如下 23 个函数可以实现 FreeRTOS 的消息队列:

 xQueueCreateStatic()
 vQueueDelete()
 xQueueSend() 

 xQueueSendFromISR()
 xQueueSendToBack()
 xQueueSendToBackFromISR()
 xQueueSendToFront()
 xQueueSendToFrontFromISR()
 xQueueReceive()
 xQueueReceiveFromISR()
 uxQueueMessagesWaiting()
 uxQueueMessagesWaitingFromISR()
 uxQueueSpacesAvailable()
 xQueueReset()
 xQueueOverwrite()
 xQueueOverwriteFromISR()
 xQueuePeek()
 xQueuePeekFromISR()
 vQueueAddToRegistry()
 vQueueUnregisterQueue()
 pcQueueGetName()
 xQueueIsQueueFullFromISR()
 xQueueIsQueueEmptyFromISR()

  关于这 23 个函数的讲解及其使用方法可以看 FreeRTOS 在线版手册:

这里重点的说以下 4 个函数:

 xQueueCreate ()
 xQueueSend ()
 xQueueSendFromISR ()
 xQueueReceive ()

 2.1  函 数 xQueueCreate

函数原型:
QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength, /* 消息个数 */
               UBaseType_t uxItemSize ); /* 每个消息大小,单位字节 */
函数描述:
函数 xQueueCreate 用于创建消息队列。
 第 1 个参数是消息队列支持的消息个数。
 第 2 个参数是每个消息的大小,单位字节。 

 返回值,如果创建成功会返回消息队列的句柄,如果由于 FreeRTOSConfig.h 文件中 heap 大小不足,
无法为此消息队列提供所需的空间会返回 NULL。
使用这个函数要注意以下问题:
1. FreeRTOS 的消息传递是数据的复制,而不是传递的数据地址,这点要特别注意。每一次传递都是uxItemSize 个字节。

使用举例:


static QueueHandle_t xQueue1 = NULL;
static QueueHandle_t xQueue2 = NULL;
/*
*********************************************************************************************************
*  函 数 名: AppObjCreate
*  功能说明: 创建任务通信机制
*  形 参: 无
*  返 回 值: 无
*********************************************************************************************************
*/
static void AppObjCreate (void)
{
  /* 创建 10 个 uint8_t 型消息队列 */
  xQueue1 = xQueueCreate(10, sizeof(uint8_t));
if( xQueue1 == 0 )
{
/* 没有创建成功,用户可以在这里加入创建失败的处理机制 */
}
/* 创建 10 个存储指针变量的消息队列,由于 CM3/CM4 内核是 32 位机,一个指针变量占用 4 个字节 */
xQueue2 = xQueueCreate(10, sizeof(struct Msg *));
if( xQueue2 == 0 )
{
/* 没有创建成功,用户可以在这里加入创建失败的处理机制 */
}
}  

2.2  函 数 xQueueSend

函数原型:
BaseType_t xQueueSend(
            QueueHandle_t xQueue, /* 消息队列句柄 */
            const void * pvItemToQueue, /* 要传递数据地址 */
            TickType_t xTicksToWait /* 等待消息队列有空间的最大等待时间 */
            );
函数描述:
函数 xQueueSend 用于任务中消息发送。
 第 1 个参数是消息队列句柄。
 第 2 个参数要传递数据地址,每次发送都是将消息队列创建函数 xQueueCreate 所指定的单个消息大小复制到消息队列空间中。 

 第 3 个参数是当消息队列已经满时,等待消息队列有空间时的最大等待时间,单位系统时钟节拍。
 返回值,如果消息成功发送返回 pdTRUE,否则返回 errQUEUE_FULL。 

使用这个函数要注意以下问题:
1. FreeRTOS 的消息传递是数据的复制,而不是传递的数据地址
2. 此函数是用于任务代码中调用的,故不可以在中断服务程序中调用此函数,中断服务程序中使用的是xQueueSendFromISR。
3. 如果消息队列已经满且第三个参数为 0,那么此函数会立即返回
4. 如果用户将 FreeRTOSConfig.h 文件中的宏定义 INCLUDE_vTaskSuspend 配置为 1 且第三个参数配置为 portMAX_DELAY,那么此发送函数会永久等待直到消息队列有空间可以使用。
5. 消息队列还有两个函数 xQueueSendToBack 和 xQueueSendToFront,函数 xQueueSendToBack实现的是 FIFO 方式的存取,函数 xQueueSendToFront 实现的是 LIFO 方式的读写。我们这里说的函数 xQueueSend 等效于 xQueueSendToBack,即实现的是 FIFO 方式的存取。

使用举例:

 


static QueueHandle_t xQueue1 = NULL;
static QueueHandle_t xQueue2 = NULL;
typedef struct Msg
{
  uint8_t ucMessageID;
  uint16_t usData[2];
  uint32_t ulData[2];
}MSG_T;
MSG_T g_tMsg;
/* 定义一个结构体用于消息队列 */ /* ********************************************************************************************************* * 函 数 名: vTaskTaskUserIF * 功能说明: 接口消息处理。 * 形 参: pvParameters 是在创建该任务时传递的形参 * 返 回 值: 无 * 优 先 级: 1 (数值越小优先级越低,这个跟uCOS相反) ********************************************************************************************************* */ static void vTaskTaskUserIF(void *pvParameters) { MSG_T *ptMsg; uint8_t ucCount = 0; /* 初始化结构体指针 */ ptMsg = &g_tMsg; /* 初始化数组 */ ptMsg->ucMessageID = 0; ptMsg->ulData[0] = 0; ptMsg->usData[0] = 0; while(1) { if(ucKeyCode == 1) { ucCount++; /* 向消息队列发数据,如果消息队列满了,等待10个时钟节拍 */ if( xQueueSend(xQueue1, (void *) &ucCount, (TickType_t)10) != pdPASS ) { /* 发送失败,即使等待了10个时钟节拍 */ printf("K1键按下,向xQueue1发送数据失败,即使等待了10个时钟节拍\r\n"); } else { /* 发送成功 */ printf("K1键按下,向xQueue1发送数据成功\r\n"); } ucKeyCode = 0; } /* K2键按下 启动单次定时器中断,50ms后在定时器中断将任务vTaskLED恢复 */ if(ucKeyCode == 2) { ptMsg->ucMessageID++; ptMsg->ulData[0]++;; ptMsg->usData[0]++; /* 使用消息队列实现指针变量的传递 */ if(xQueueSend(xQueue2, /* 消息队列句柄 */ (void *) &ptMsg, /* 发送结构体指针变量ptMsg的地址 */ (TickType_t)10) != pdPASS ) { /* 发送失败,即使等待了10个时钟节拍 */ printf("K2键按下,向xQueue2发送数据失败,即使等待了10个时钟节拍\r\n"); } else { /* 发送成功 */ printf("K2键按下,向xQueue2发送数据成功\r\n"); } ucKeyCode = 0; } vTaskDelay(20); } }

 

2.3  函 数 xQueueSendFromISR

函数原型:
BaseType_t xQueueSendFromISR
               (
                QueueHandle_t xQueue, /* 消息队列句柄 */
                const void *pvItemToQueue, /* 要传递数据地址 */
                BaseType_t *pxHigherPriorityTaskWoken /* 高优先级任务是否被唤醒的状态保存 */
               );
函数描述:
函数 xQueueSendFromISR 用于中断服务程序中消息发送。
 第 1 个参数是消息队列句柄。
 第 2 个参数要传递数据地址,每次发送都是将消息队列创建函数 xQueueCreate 所指定的单个消息大小复制到消息队列空间中。
 第3个参数用于保存是否有高优先级任务准备就绪。如果函数执行完毕后,此参数的数值是pdTRUE,说明有高优先级任务要执行,否则没有。
 返回值,如果消息成功发送返回 pdTRUE,否则返回 errQUEUE_FULL。
使用这个函数要注意以下问题:
1. FreeRTOS 的消息传递是数据的复制,而不是传递的数据地址。正因为这个原因,用户在创建消息队列时单个消息大小不可太大,因为一定程度上面会增加中断服务程序的执行时间
2. 此函数是用于中断服务程序中调用的,故不可以在任务代码中调用此函数,任务代码中使用的是xQueueSend。
3. 消息队列还有两个函数 xQueueSendToBackFromISR 和 xQueueSendToFrontFromISR,函数xQueueSendToBackFromISR 实现的是 FIFO 方式的存取,函数 xQueueSendToFrontFromISR 实现的是 LIFO 方式的读写。我们这里说的函数 xQueueSendFromISR 等效于
xQueueSendToBackFromISR,即实现的是 FIFO 方式的存取。

使用举例:

 


void  BASIC_TIMx_IRQHandler(void)
{
    if(1 == temp)
    {
        TIM_ClearITPendingBit(BASIC_TIMx , TIM_IT_Update);
        
        TIM_ITConfig(BASIC_TIMx,TIM_IT_Update,DISABLE);
        
        BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    
        g_uiCount++;
    
        /* 向消息队列发数据 */
        xQueueSendFromISR(xQueue1,
                                (void *)&g_uiCount,
                                &xHigherPriorityTaskWoken);

        /* 如果xHigherPriorityTaskWoken = pdTRUE,那么退出中断后切到当前最高优先级任务执行 */
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);    
        
    }
    if(2 == temp)
    {
        TIM_ClearITPendingBit(BASIC_TIMx , TIM_IT_Update);
        
        TIM_ITConfig(BASIC_TIMx,TIM_IT_Update,DISABLE);
        
        MSG_T   *ptMsg;
        BaseType_t xHigherPriorityTaskWoken = pdFALSE;
        
        /* 初始化结构体指针 */
        ptMsg = &g_tMsg;
        
        /* 初始化数组 */
        ptMsg->ucMessageID++;
        ptMsg->ulData[0]++;
        ptMsg->usData[0]++;

        /* 向消息队列发数据 */
        xQueueSendFromISR(xQueue2,
                                (void *)&ptMsg,
                                 &xHigherPriorityTaskWoken);

        /* 如果xHigherPriorityTaskWoken = pdTRUE,那么退出中断后切到当前最高优先级任务执行 */
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);            
        
    }

}  

 

 

 

2.4  函 数 xQueueReceive

函数原型:
BaseType_t xQueueReceive(
             QueueHandle_t xQueue, /* 消息队列句柄 */
             void *pvBuffer, /* 接收消息队列数据的缓冲地址 */
             TickType_t xTicksToWait /* 等待消息队列有数据的最大等待时间 */
             );
函数描述:
函数 xQueueReceive 用于接收消息队列中的数据。
 第 1 个参数是消息队列句柄。
 第 2 个参数是从消息队列中复制出数据后所储存的缓冲地址,缓冲区空间要大于等于消息队列创建函数 xQueueCreate 所指定的单个消息大小,否则取出的数据无法全部存储到缓冲区,从而造成内存溢出。
 第 3 个参数是消息队列为空时,等待消息队列有数据的最大等待时间,单位系统时钟节拍。
 返回值,如果接收到消息返回 pdTRUE,否则返回 pdFALSE。
使用这个函数要注意以下问题:
1. 此函数是用于任务代码中调用的,故不可以在中断服务程序中调用此函数,中断服务程序使用的是xQueueReceiveFromISR。
2. 如果消息队列为空且第三个参数为 0,那么此函数会立即返回。
3. 如果用户将 FreeRTOSConfig.h 文件中的宏定义 INCLUDE_vTaskSuspend 配置为 1 且第三个参数配置为 portMAX_DELAY,那么此函数会永久等待直到消息队列有数据。

 使用举例:

 


/*
*********************************************************************************************************
*    函 数 名: vTaskMsgPro
*    功能说明: 消息处理,使用函xQueueReceive接收任务vTaskTaskUserIF消息队列中的数据。
*    形    参: pvParameters 是在创建该任务时传递的形参
*    返 回 值: 无
*   优 先 级: 3  
*********************************************************************************************************
*/
static void vTaskMsgPro(void *pvParameters)
{
    BaseType_t xResult;
    const TickType_t xMaxBlockTime = pdMS_TO_TICKS(300); /* 设置最大等待时间为300ms */
    uint8_t ucQueueMsgValue;
    
    while(1)
    {
        xResult = xQueueReceive(xQueue1,                   /* 消息队列句柄 */
                                (void *)&ucQueueMsgValue,  /* 存储接收到的数据到变量ucQueueMsgValue中 */
                                (TickType_t)xMaxBlockTime);/* 设置阻塞时间 */
        
        if(xResult == pdPASS)
        {
            /* 成功接收,并通过串口将数据打印出来 */
            printf("接收到消息队列数据ucQueueMsgValue = %d\r\n", ucQueueMsgValue);
        }
        else
        {
            BEEP_TOGGLE;            
        }
    }
}  

 


void vTaskLed1(void *pvParameters)
{
    
    MSG_T *ptMsg;
    BaseType_t xResult;
    const TickType_t xMaxBlockTime = pdMS_TO_TICKS(200); /* 设置最大等待时间为200ms */
    
    while(1)
    {
        xResult = xQueueReceive(xQueue2,                   /* 消息队列句柄 */
                                (void *)&ptMsg,             /* 这里获取的是结构体的地址 */
                                (TickType_t)xMaxBlockTime);/* 设置阻塞时间 */
        
        
        if(xResult == pdPASS)
        {
            /* 成功接收,并通过串口将数据打印出来 */
            printf("接收到消息队列数据ptMsg->ucMessageID = %d\r\n", ptMsg->ucMessageID);
            printf("接收到消息队列数据ptMsg->ulData[0] = %d\r\n", ptMsg->ulData[0]);
            printf("接收到消息队列数据ptMsg->usData[0] = %d\r\n", ptMsg->usData[0]);
        }
        else
        {
            /* 超时 */
            LED1_TOGGLE;            
        }
    
    }    
}  

实验通过AppObjCreate函数创建两个队列消息,容量都是10个消息,队列1,2分别为uint8_t和struct Msg *类型,按键K1,实现队列1一个计数的增加,然后在Beep任务中接收这个变化的值,任务2实现结构体元素的增加,在LED任务中接收这个增量并打印出来。需要说明的是,freertos消息队列是通过副本机制传递的,而不是引用,

我们查看底层实现,

freertos通过使用memcpy复制的内容。以简单的数据元素为例:

uint8_t ucCount = 0;

xQueueSend(xQueue1,(void *) &ucCount,(TickType_t)10)

这里是发送队列消息函数,下面看接收:

uint8_t ucQueueMsgValue; 

xQueueReceive(xQueue1, /* 消息队列句柄 */
(void *)&ucQueueMsgValue, /* 存储接收到的数据到变量ucQueueMsgValue中 */
(TickType_t)xMaxBlockTime)

这里是最简单的uint_8类型元素,要想把发送函数的uint_8定义的数据,包括该数据在发送函数之前被更改后的值发送给接收函数,我们需要传递给发送函数send一个uint_8定义数据的地址,这样可以通过地址传递到memcpy函数,实现复制,这也就是为什么上面说的freertos的消息队列不是引用而是复制,要是引用的话,可以直接传这个uint_8类型的数据,而我们此时在freertos操作系统上,是副本传递,通过memcpy,所以需要给uint_8类型数据的地址。

这个或许并不具有什么迷惑性,但是,官方的参考demo,要是不认真理解一下,是想不通的。

在本次实验中传递一个结构体就是官方的参考历程:

发送函数:

MSG_T   *ptMsg;//MSG是个结构体

ptMsg = &g_tMsg;//g_tMsg是一个结构实体而且是全局区定义的

/* 初始化数组 */
ptMsg->ucMessageID = 0;
ptMsg->ulData[0] = 0;
ptMsg->usData[0] = 0;

xQueueSend(xQueue2, /* 消息队列句柄 */
(void *) &ptMsg, /* 发送结构体指针变量ptMsg的地址 */
(TickType_t)10)

 接收函数:

MSG_T *ptMsg;

xQueueReceive(xQueue2, /* 消息队列句柄 */
(void *)&ptMsg, /* 这里获取的是结构体的地址 */
(TickType_t)xMaxBlockTime);/* 设置阻塞时间 */

这里的关键就在第二个参数ptMsg,它已经是指针了,为什么还要取地址,这样不是一个二级指针了吗,而它的参数是void *,给人的感觉应该就是传一个地址,虽然二级指针也是地址,但是总觉得不应该设计成二级指针赋值给一个一级指针,哪怕你是void*。但是我们既然使用了freertos,就要遵循别人的设计,别人这样做,肯定有自己的道理,我们做到熟练应用即可。试想,消息发送函数,要发送数据,要得到这个数据的地址以给memcopy,如果传递的数据本身就是地址(指针),那么我们要把这个地址传到接收函数去,就应该得到此时指针的地址才行,也就是传递一个指针的值,注意不是指针指向的值。关键我们要通过memcpy函数,传递一个指针的值通过memcpy必然是需要二级指针的,这样才可以操作一级指针的值,这样也就可以理解为什么ptMsg已经是指针了,却还是要传递ptMsg的地址,因为只有这样,才可以通过memcpy函数把ptMsg指针的值给到接收函数的指针,这样在接收函数中操作这个结构体类型的指针,就可以得到发送端的数据。这样做的好处是,避免了大数据的拷贝,只拷贝指针,提高了效率,但是使用指针,一定不要在栈空间开辟,这也是为什么我们定义g_tMsg结构体实体在全局区。但是freertos任务中一直有while(1),元素生命周期一直都在,此时还是可以使用局部变量做数据传递工具,但是这样的编程模式应该摒弃,我们采用全局区开辟的空间。更多参见下一篇随笔。

那么你可能会问了,那我直接给指针ptMsg看看行不行呢,不给指针的地址即&ptMsg。答案是肯定的,不行。给ptMsg,相当于把ptMsg指向的数据给了接收端,而freertos要求是的,你传一个你想要发送消息的地址,我们想要发送的消息是ptMsg,它的地址是&ptMsg,所以我们必须传递&ptMsg。并不能简单看类型是否完全贴切,要看源码内部实现,毕竟强制类型转换太霸道。

再者,你还是觉得这样很诧异,那么你可以使用结构,而不要使用结构体指针,这样你传递的时候就是这个结构的指针了。但是注意,使用结构本身不使用结构体指针的时候,创建消息队列里面的siezof要改成结构体而不再是上面的结构体指针:

xQueue2 = xQueueCreate(10, sizeof(struct Msg ));

当然后面的->操作,要改成 . 操作。

实验现象如下:

 

 

 最后说两句:

 而我测试了,深度给1,但我发送两个消息,程序还是可以工作,(并不是我给队列深度为1,就只能有一个队列消息发送函数)这和发送接收的允许阻塞时间有关。

 

所以,在等待时间合适的情况下,深度只给1,还是可以发送多次的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

FreeRTOS — 消息队列 的相关文章

  • RabbitMQ:Queue的介绍和使用

    1 声明 当前内容用于本人学习和使用当前的Queue 当前内容为RabbitMQ中对Queue的介绍 当前内容来源 RabbitMQ中的Queue 2 Queue的官方介绍 首先先分析以下前面的Queue的使用 其实这个东西就是一个队列 一
  • FreeRTOS临界段和开关中断

    http blog sina com cn s blog 98ee3a930102wg5u html 本章教程为大家讲解两个重要的概念 FreeRTOS的临界段和开关中断 本章教程配套的例子含Cortex M3内核的STM32F103和Co
  • rocketMq消息队列原生api使用以及rocketMq整合springboot

    rocketMq消息队列 文章目录 rocketMq消息队列 一 RocketMQ原生API使用 1 测试环境搭建 2 RocketMQ的编程模型 3 RocketMQ的消息样例 3 1 基本样例 3 2 顺序消息 3 3 广播消息 3 4
  • 7 SpringBoot整合RocketMQ发送单向消息

    发送单向消息是指producer向 broker 发送消息 执行 API 时直接返回 不等待broker 服务器的结果 这种方式主要用在不特别关心发送结果的场景 举例 日志发送 RocketMQTemplate给我们提供了sendOneWa
  • STM32F103移植FreeRTOS必须搞明白的系列知识---2(FreeRTOS任务优先级)

    STM32F103移植FreeRTOS必须搞明白的系列知识 1 Cortex CM3中断优先级 STM32F103移植FreeRTOS必须搞明白的系列知识 2 FreeRTOS任务优先级 STM32F103移植FreeRTOS必须搞明白的系
  • RocketMQ消费重试问题

    异常现象 监控日志展示如下 2019 10 30 14 31 23 339 INFO ConsumeMessageThread 7 com xxx service mq MQConsumerService 93 消费消息 msgId 0A0
  • FreeRTOS笔记(一)简介

    这个笔记主要依据韦东山freertos快速入门系列记录 感谢韦东山老师的总结 什么是实时操作系统 操作系统是一个控制程序 负责协调分配计算资源和内存资源给不同的应用程序使用 并防止系统出现故障 操作系统通过一个调度算法和内存管理算法尽可能把
  • FreeRTOS学习笔记(8)---- 软件定时器

    使用FreeRTOS软件定时器需要在文件FreeRTOSConfig h先做如下配置 1 configUSE TIMERS 使能软件定时器 2 configTIMER TASK PRIORITY 定时器任务优先级 3 configTIMER
  • Java 项目的跨库的方式查询的方法

    Java 项目的跨库的方式查询的方法 目录 概述 需求 设计思路 实现思路分析 性能参数测试 参考资料和推荐阅读 Survive by day and develop by night talk for import biz show yo
  • RocketMQ 简介

    本文根据阿里云 RocketMQ产品文档整理 地址 https help aliyun com document detail 29532 html userCode qtldtin2 简介 RocketMQ是由阿里捐赠给Apache的一款
  • 消息队列:Ubuntu16.04安装和Web页面管理RabbitMQ(楼主亲测、真实有效)

    RabbitMQ 总来来说 RabbitMQ的安装还是有一些难度的 不同的方式 安装的方法也是完全不一样 还要解决蛮多依赖 加上现在有些网站 极其不负责 很多博文都没有经过测试检验就直接发出来的 楼主来亲测一下 希望能对大家有好的帮助 一
  • freeRTOS出现任务卡死的情况。

    最近在做一个产品二代升级的项目 代码是上一任工程师留下的 很多BUG 而且融合了HAL库和LL库 以及github上下载的GSM源码 很不好用 我这边是将2G模块换成了4G 且添加了单独的BLE模块 因此只在源码的基础上 去除2G和BLE代
  • FreeRTOS轻量级同步--任务通知

    1 简介 在FreeRTOS的配置参数中的configUSE TASK NOTIFICATIONS宏打开 一般RTOS会默认打开 如图1所示 图1 notify宏开关 RTOS在创建任务时 会创建一个32位的通知值ulNotifiedVal
  • RocketMQ系列之架构浅谈

    RMQ的架构设计 下面我从GitHub上截取了一张RMQ的源码结构图 图中我框框出来的9大模块 基本就构成了整个RMQ的内部结构 上面9大模块的依赖层次主要如下 依赖越强的越处于底层 下面介绍下最上层的4个模块 这4个模块中工具命令行就不讲
  • RocketMQ-高级原理

    本节讲解下当MQ消息消费失败 或者发送不成功时如何处理消息 消息发送不成功一般存在于几种情况 网络原因 服务宕机 或者broker配置 消息发送失败 如果是由于broker配置原因 可以通过报错提示排查原因 无法查到路由信息 一般考虑到ro
  • ESP32学习笔记05-串口事件方式读取数据

    串口中断方式处理数据 事件机构体 typedef struct uart event type t type lt UART event type size t size lt UART data size for UART DATA ev
  • kafka系列——KafkaProducer源码分析

    实例化过程 在KafkaProducer的构造方法中 根据配置项主要完成以下对象或数据结构的实例化 配置项中解析出 clientId 用于跟踪程序运行情况 在有多个KafkProducer时 若没有配置 client id则clientId
  • FreeRTOSConfig.h 配置优化及深入

    本篇目标 基于上一篇的移植freertos stm32f4 freertos 上 修改 FreeRTOSConfig h 文件的相关配置来优化辅助 FreeRtos 的使用 并且建立一些基本功能 信号量 消息地列等 的简单应用位于 stm3
  • 如何更改 FreeRTOS 中任务的最大可用堆大小?

    我通过以下方式在任务中创建元素列表 l dllist pvPortMalloc sizeof dllist dlllist 有 32 字节大 我的嵌入式系统有 60kB SRAM 所以我希望系统可以轻松处理我的 200 个元素列表 我发现在
  • 有可用的 FreeRTOS 解释语言库吗?

    我在一家公司工作 该公司使用 FreeRTOS 为多个设备创建固件 最近 我们对新功能的要求已经超出了我们固件工程师的工作能力 但我们现在也无力雇用任何新人 即使进行微小的更改 也需要固件人员在非常低的级别上进行修改 我一直在为 FreeR

随机推荐

  • TVM编译与python环境配置

    提示 xff1a 仅记录一下本次成功安装的过程用于参考 目录 前言 一 源码下载 二 编译 1 安装依赖 2 安装llvm 3 开始编译 4 设置python环境 前言 记录一下tvm的编译流程与python环境安装 环境 xff1a ro
  • apache反向代理tomcat时x-forwarded-for为null的问题

    apache 在用ProxyPass时会自动在header中设置X Forwarded For X Forwarded Host和X Forwarded Server xff08 http httpd apache org docs 2 2
  • APP_CTL_HEAP_SZ 堆中没有足够的存储器可用来处理语句

    Caused by COM ibm db2 jdbc DB2Exception IBM CLI Driver DB2 NT SQL0973N 34 APP CTL HEAP SZ 34 堆中没有足够的存储器可用来处理语句 SQLSTATE
  • OpenCV颜色识别

    彩色模型 数字图像处理中常用的采用模型是RGB xff08 红 xff0c 绿 xff0c 蓝 xff09 模型和HSV xff08 色调 xff0c 饱和度 xff0c 亮度 xff09 xff0c RGB广泛应用于彩色监视器和彩色视频摄
  • vmware占用磁盘空间增加(ubuntu虚拟机占用空间小)

    vmware占用磁盘空间大 xff0c 但是用df h指令看ubuntu虚拟机占用的空间没有这么大 xff0c 可以试着用下面的三种方法清理vmware占用的空间 方法一 xff1a 使用vmware自带的工具就能收回占用的部分空间 那个工
  • 进临界区(关全局中断)是否会影响数据的接收?

    在嵌入式的编程中 xff0c 经常会使用嵌入式实时操作系统 xff0c 比如FreeRTOS xff0c RTT等 而在使用这些操作系统时 xff0c 会有一个临界区的概念 xff0c 一般操作是 1 xff0c 进入临界区 xff1b 2
  • source insight 4.0 护眼背景色设置

    1 xff0c 打开source insight 4 0 2 xff0c 选择options下的preferences 3 xff0c 选择window background xff0c 双击打开 xff1b 4 xff0c 在颜色中将色调
  • octet和byte

    在看BLE协议时 xff0c 看到了数据包格式的定义 packet format xff0c 定义如下 xff1a Preamble 1 octet Access Address 4 octets PDU 2 to 257 octets C
  • 如何解决SSL/TLS握手过程中失败的错误?

    Fixes for the SSL TLS Handshake Failed error for both internet users and site owners It s time for another technical art
  • 学校人力资源管理系统——逻辑结构设计

    E R 图向关系模型的转换 第一步 把六个实体类型转化成五个模式 xff1a 教职工 职工编号 xff0c 姓名 xff0c 性别 xff0c 出生年份 xff0c 学历 xff0c 民族 xff0c 婚姻状态 xff0c 政治面貌 xff
  • 无线持续攻击(wireless duration attack)

    抓空口包时发现一种奇怪的ack帧 duration位长度是32767us 看到omnipeek将它定义为wireless duration attack 看起来是路由器回复设备的ack 而设备也是发了一个奇怪的pspoll帧 节能位置1 乱
  • .bashrc文件在哪?

    linux的bashrc文件在 home目录下 xff0c 但是是一个隐藏bai文件 xff0c 在文件管理器里面du按Ctrl 43 H即可显示 显示为 bashrc xff0c 前zhi面小点儿表示隐藏文件 xff09 也可以直接利用t
  • Cotex-M内核双堆栈指针MSP和PSP

    MSP和PSP 的含义是Main Stack Pointer 和Process Stack Pointer 在逻辑地址上他们都是R13 xff1b 权威手册上说的很清楚PSP主要是在Handler的模式下使用 xff0c MSP主要在线程模
  • TCP/IP协议栈之LwIP-pbuf

    pbuf结构体就是一个描述协议栈中数据包的数据结构 xff1a Main packet buffer struct struct pbuf next pbuf in singly linked pbuf chain struct pbuf
  • Linux使用wpa_supplicant手动配置连接WiFi

    wpa supplicant是Linux BSD Mac OSX和Windows的WPA的服务 支持WPA和WPA2 IEEE 802 11i RSN xff0c 它适用于台式机 笔记本和嵌入式系统 xff0c Supplicant是在客户
  • 使用python快速将主机字节序转为网络字节序

    1 进入python环境 这里以win10自带的wsl win10子系统为操作环境进入Python命令行 2 引入网络字节序标准库 这里使用Python自带的socket库 3 将待转换的主机数据使用socket htons 或者socke
  • ∏这个是什么符号?

    是各项连乘的运算符号 读大写的 xff08 pai xff09 例如 xff1a i 61 1 xff08 符号下面 xff09 n xff08 符号上面 xff09 ai 符号右面 表示a1 a2 an 符号下面表示右面式子可变参量的下限
  • python获取图片的颜色信息

    span class pun style font family none font size 14px span h1 style font family none font size 24px padding 5px margin 5p
  • Python:TypeError: 'int' object is not callable

    一个函数的部分代码如下 xff1a python view plain copy def loadData len 61 dataSet len trainingSet extend dataSet len 3 4 testSet exte
  • FreeRTOS — 消息队列

    以下内容转载自安富莱电子 xff1a http forum armfly com forum php FreeRTOS 的一个重要的通信机制 消息队列 xff0c 消息队列在实际项目中应用较多 1 消息队列 1 1 消息队列的概念及其作用