<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>RTOS on Zesean 的博客</title><link>https://zeseanblog.top/tags/rtos/</link><description>Recent content in RTOS on Zesean 的博客</description><generator>Hugo -- gohugo.io</generator><language>zh-CN</language><lastBuildDate>Tue, 01 Sep 2026 22:58:08 +0800</lastBuildDate><atom:link href="https://zeseanblog.top/tags/rtos/index.xml" rel="self" type="application/rss+xml"/><item><title>FreeRTOS 源码解析笔记</title><link>https://zeseanblog.top/p/freertos-source/</link><pubDate>Sat, 09 Aug 2025 10:00:00 +0800</pubDate><guid>https://zeseanblog.top/p/freertos-source/</guid><description>&lt;h1 id="1动态创建详细过程"&gt;&lt;a href="#1%e5%8a%a8%e6%80%81%e5%88%9b%e5%bb%ba%e8%af%a6%e7%bb%86%e8%bf%87%e7%a8%8b" class="header-anchor"&gt;&lt;/a&gt;1.动态创建详细过程&#13;&#10;&lt;/h1&gt;&lt;h2 id="动态创建"&gt;&lt;a href="#%e5%8a%a8%e6%80%81%e5%88%9b%e5%bb%ba" class="header-anchor"&gt;&lt;/a&gt;动态创建&#13;&#10;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;1.首先tasks.c中&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;结构体并给别名，所以初始化可以用TCB_t&lt;/p&gt;&#10;&lt;p&gt;typedef struct tskTaskControlBlock&lt;/p&gt;&#10;&lt;p&gt;{&lt;/p&gt;&#10;&lt;p&gt;&amp;hellip;&lt;/p&gt;&#10;&lt;p&gt;}tskTCB;&#10;typedef tskTCB TCB_t;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;2.因此在xTaskCreate()实现中&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;TCB_t * pxNewTCB;创建了任务控制块&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;3.任务控制块的结构体中&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;状态列表 事件列表 优先级 栈指针 任务名&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250802183613953" class="gallery-image" data-flex-basis="1029px" data-flex-grow="428" height="90" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos-source/images/image-20250802183613953.png" width="386"&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;4.回到xTaskCreate&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;判断生长方向，STM32栈区向下生长&lt;/p&gt;&#10;&lt;p&gt;#if ( portSTACK_GROWTH &amp;gt; 0 )&lt;/p&gt;&#10;&lt;p&gt;进入的&lt;/p&gt;&#10;&lt;p&gt;#else中&lt;/p&gt;&#10;&lt;p&gt;其中先定义任务堆栈大小：&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;StackType_t * pxStack;//这个申请的代表首地址&#10;&#10;pxStack = pvPortMallocStack( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) );//如128*4字节，128字×每字字节数=字节数&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;判断是否申请成功任务堆栈，成功则进入&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt; if( pxStack != NULL )&#10; {&#10; pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); //任务控制块信息也需要空间，因此申请&#10; if( pxNewTCB != NULL ) //如果申请了一块&#10; {&#10; memset( ( void * ) pxNewTCB, 0x00, sizeof( TCB_t ) );&#10; pxNewTCB-&amp;gt;pxStack = pxStack;//然后将首地址给到任务控制块的这个成员变量&#10; }&#10; else&#10; {&#10; vPortFreeStack( pxStack );//否则就释放掉任务堆栈&#10; }&#10; }&#10; else&#10; {&#10; pxNewTCB = NULL;&#10; }&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;再下面判断是否申请成功任务控制块&lt;/p&gt;&#10;&lt;p&gt;prvInitialiseNewTask：这个用来初始化任务控制块中的成员&lt;/p&gt;&#10;&lt;p&gt;prvAddNewTaskToReadyList：将任务添加到就绪列表&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt; if( pxNewTCB != NULL )&#10; {&#10; prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL );&#10; prvAddNewTaskToReadyList( pxNewTCB );&#10; xReturn = pdPASS;//就是成功的返回值&#10; }&#10; else&#10; {&#10; xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;&#10; }&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;5.到prvInitialiseNewTask&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;( void ) memset( pxNewTCB-&amp;gt;pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) ulStackDepth * sizeof( StackType_t ) );&lt;/p&gt;&#10;&lt;p&gt;这句pxStack是任务堆栈的首地址，将( size_t ) ulStackDepth * sizeof( StackType_t )大小的地址赋值为( int ) tskSTACK_FILL_BYTE&lt;/p&gt;&#10;&lt;p&gt;而这个值是&lt;/p&gt;&#10;&lt;p&gt;#define tskSTACK_FILL_BYTE ( 0xa5U )&lt;/p&gt;&#10;&lt;p&gt;意思就是整个任务堆栈赋值成a5，那就可以通过判断多少a5被改变，得到剩下的空间&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;6.判断 #if ( portSTACK_GROWTH &amp;lt; 0 )&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;是否向下生长？&lt;/p&gt;&#10;&lt;p&gt;STM32:是的&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;//首地址的最低位，取得栈顶&#10;pxTopOfStack = &amp;amp;( pxNewTCB-&amp;gt;pxStack[ ulStackDepth - ( uint32_t ) 1 ] );&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;判断名字是否为空&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;//pcName是一个入口参数&#10;if( pcName != NULL )&#10; {&#10; for( x = ( UBaseType_t ) 0; x &amp;lt; ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ )&#10; {&#10; pxNewTCB-&amp;gt;pcTaskName[ x ] = pcName[ x ]; //给到任务控制块的这个成员里&#10; if( pcName[ x ] == ( char ) 0x00 )&#10; {&#10; break;&#10; }&#10; else&#10; {&#10; mtCOVERAGE_TEST_MARKER();&#10; }&#10; }&#10; pxNewTCB-&amp;gt;pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = &amp;#39;\0&amp;#39;;&#10; }&#10; else&#10; {&#10; mtCOVERAGE_TEST_MARKER();&#10; }&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;判断优先级&lt;/p&gt;&#10;&lt;p&gt;优先级大于最大优先级，就改为最大优先级&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;if( uxPriority &amp;gt;= ( UBaseType_t ) configMAX_PRIORITIES )&#10; {&#10; uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;&#10; }&#10;&#10;pxNewTCB-&amp;gt;uxPriority = uxPriority;&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;然后初始化状态列表项和事件列表项&lt;/p&gt;&#10;&lt;p&gt;vListInitialiseItem( &amp;amp;( pxNewTCB-&amp;gt;xStateListItem ) );&#10;vListInitialiseItem( &amp;amp;( pxNewTCB-&amp;gt;xEventListItem ) );&lt;/p&gt;&#10;&lt;p&gt;将状态列表项所有权给到任务控制块，就可以得到任务当前状态&lt;/p&gt;&#10;&lt;p&gt;listSET_LIST_ITEM_OWNER( &amp;amp;( pxNewTCB-&amp;gt;xStateListItem ), pxNewTCB );&lt;/p&gt;&#10;&lt;p&gt;下面是事件列表项&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;listSET_LIST_ITEM_VALUE( &amp;amp;( pxNewTCB-&amp;gt;xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority ); &#10; listSET_LIST_ITEM_OWNER( &amp;amp;( pxNewTCB-&amp;gt;xEventListItem ), pxNewTCB );&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;下面来到&lt;/p&gt;&#10;&lt;p&gt;pxNewTCB-&amp;gt;pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;7.进入pxPortInitialiseStack&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;里面栈顶陆续减，就可以往下陆续给赋值。&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,&#10; TaskFunction_t pxCode,&#10; void * pvParameters )&#10;{&#10; &#10; pxTopOfStack--; &#10; *pxTopOfStack = portINITIAL_XPSR; /* xPSR */&#10; pxTopOfStack--;&#10; *pxTopOfStack = ( ( StackType_t ) pxCode ) &amp;amp; portSTART_ADDRESS_MASK; /* PC */&#10; pxTopOfStack--;&#10; *pxTopOfStack = ( StackType_t ) prvTaskExitError; /* LR */&#10;&#10; pxTopOfStack -= 5; /* R12, R3, R2 and R1. */&#10; *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */&#10; pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */&#10;&#10; return pxTopOfStack;&#10;}&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;PC是任务函数指针&lt;/strong&gt;，切换到A任务时，就通过这个指针切换到任务函数A&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250802194920338" class="gallery-image" data-flex-basis="545px" data-flex-grow="227" height="708" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos-source/images/image-20250802194920338.png" srcset="https://zeseanblog.top/p/freertos-source/images/image-20250802194920338_hu_381901ee71d0b455.png 800w, https://zeseanblog.top/p/freertos-source/images/image-20250802194920338_hu_50975814e2aa1c3e.png 1600w, https://zeseanblog.top/p/freertos-source/images/image-20250802194920338.png 1610w" width="1610"&gt;&lt;/p&gt;&#10;&lt;p&gt;这个实际就是最初传入的函数指针&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250802195354593" class="gallery-image" data-flex-basis="1260px" data-flex-grow="525" height="119" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos-source/images/image-20250802195354593.png" width="625"&gt;&lt;/p&gt;&#10;&lt;p&gt;而R0传入的是任务函数参数&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250802195543474" class="gallery-image" data-flex-basis="1208px" data-flex-grow="503" height="118" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos-source/images/image-20250802195543474.png" width="594"&gt;&lt;/p&gt;&#10;&lt;p&gt;程序结束后返回更新后的pxTopOfStack&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;8.回到prvInitialiseNewTask&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;将任务句柄给到任务控制块&lt;/p&gt;&#10;&lt;p&gt;if( pxCreatedTask != NULL )&#10;{&#10;*pxCreatedTask = ( TaskHandle_t ) pxNewTCB;&#10;}&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;9.再到prvAddNewTaskToReadyList()&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;这是将任务添加到就绪列表&lt;/p&gt;&#10;&lt;p&gt;先进入临界区 taskENTER_CRITICAL();&lt;/p&gt;&#10;&lt;p&gt;增加任务数量uxCurrentNumberOfTasks++;&lt;/p&gt;&#10;&lt;p&gt;如果当前没有任务，这是第一个任务pxCurrentTCB = pxNewTCB;&lt;/p&gt;&#10;&lt;p&gt;如果这确实是第一个if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 )&lt;/p&gt;&#10;&lt;p&gt;就初始化任务列表prvInitialiseTaskLists()&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250802201105871" class="gallery-image" data-flex-basis="491px" data-flex-grow="204" height="303" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos-source/images/image-20250802201105871.png" width="620"&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;10.进入prvInitialiseTaskLists()&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;初始化32个就绪列表0~31&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;for( uxPriority = ( UBaseType_t ) 0U; uxPriority &amp;lt; ( UBaseType_t ) configMAX_PRIORITIES; uxPriority++ )&#10; {&#10; vListInitialise( &amp;amp;( pxReadyTasksLists[ uxPriority ] ) );&#10; }&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果使能删除列表，就初始化一个等待删除列表&lt;/p&gt;&#10;&lt;p&gt;如果使能挂起列表，就初始化一个挂起列表&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;#if ( INCLUDE_vTaskDelete == 1 )&#10; {&#10; vListInitialise( &amp;amp;xTasksWaitingTermination );&#10; }&#10; #endif /* INCLUDE_vTaskDelete */&#10;&#10; #if ( INCLUDE_vTaskSuspend == 1 )&#10; {&#10; vListInitialise( &amp;amp;xSuspendedTaskList );&#10; }&#10; #endif /* INCLUDE_vTaskSuspend */&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;11.继续prvAddNewTaskToReadyList()&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;否则的话，如果当前任务控制块优先级小于新创建的任务控制块&lt;/p&gt;&#10;&lt;p&gt;那新创建的就赋给当前&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;if( xSchedulerRunning == pdFALSE )&#10; {&#10; if( pxCurrentTCB-&amp;gt;uxPriority &amp;lt;= pxNewTCB-&amp;gt;uxPriority )&#10; {&#10; pxCurrentTCB = pxNewTCB;&#10; }&#10; else&#10; {&#10; mtCOVERAGE_TEST_MARKER();&#10; }&#10; }&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;下面是任务标号，就可以通过这个查询这是第几个创建的任务&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250802201852893" class="gallery-image" data-flex-basis="967px" data-flex-grow="403" height="121" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos-source/images/image-20250802201852893.png" width="488"&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;12.进入prvAddTaskToReadyList( pxNewTCB );&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;进入 taskRECORD_READY_PRIORITY( ( pxTCB )-&amp;gt;uxPriority );&lt;/p&gt;&#10;&lt;p&gt;进如portRECORD_READY_PRIORITY&lt;/p&gt;&#10;&lt;p&gt;得到&lt;/p&gt;&#10;&lt;p&gt;#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL &amp;laquo; ( uxPriority ) )&lt;/p&gt;&#10;&lt;p&gt;表示就绪列表，哪个位置一，哪个位就有任务，从上往下读就知道哪个任务优先级最高&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250802202706272" class="gallery-image" data-flex-basis="382px" data-flex-grow="159" height="301" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos-source/images/image-20250802202706272.png" width="480"&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;13.继续prvAddNewTaskToReadyList()&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;退出临界区taskEXIT_CRITICAL();&lt;/p&gt;&#10;&lt;p&gt;如果任务调度器开启，当前任务优先级，小于新的优先级，执行任务切换，到优先级最高的&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250802202950218" class="gallery-image" data-flex-basis="750px" data-flex-grow="312" height="210" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos-source/images/image-20250802202950218.png" width="657"&gt;&lt;/p&gt;&#10;&lt;h1 id="2任务挂起与恢复详细过程"&gt;&lt;a href="#2%e4%bb%bb%e5%8a%a1%e6%8c%82%e8%b5%b7%e4%b8%8e%e6%81%a2%e5%a4%8d%e8%af%a6%e7%bb%86%e8%bf%87%e7%a8%8b" class="header-anchor"&gt;&lt;/a&gt;2.任务挂起与恢复详细过程&#13;&#10;&lt;/h1&gt;&lt;h2 id="任务挂起"&gt;&lt;a href="#%e4%bb%bb%e5%8a%a1%e6%8c%82%e8%b5%b7" class="header-anchor"&gt;&lt;/a&gt;任务挂起&#13;&#10;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;1.进入prvGetTCBFromHandle&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;如果句柄为NULL，返回当前任务控制块句柄，否则返回传入任务控制块句柄&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;#define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? pxCurrentTCB : ( pxHandle ) )&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;2.回到vTaskSuspend&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;if内是不管当前状态是什么，并移除列表项，移除成功则进入&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt; if( uxListRemove( &amp;amp;( pxTCB-&amp;gt;xStateListItem ) ) == ( UBaseType_t ) 0 )&#10; {&#10; taskRESET_READY_PRIORITY( pxTCB-&amp;gt;uxPriority );&#10; }&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;3.进入taskRESET_READY_PRIORITY&lt;/strong&gt;&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;if(listCURRENT_LIST_LENGTH(&amp;amp;(pxReadyTasksLists[( uxPriority ) ] ) ) == ( UBaseType_t ) 0 ) &#10; { &#10; portRESET_READY_PRIORITY( ( uxPriority ), ( uxTopReadyPriority ) ); &#10; } &#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;4.回到vTaskSuspend&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;移除事件列表项&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;if( listLIST_ITEM_CONTAINER( &amp;amp;( pxTCB-&amp;gt;xEventListItem ) ) != NULL )&#10; {&#10; ( void ) uxListRemove( &amp;amp;( pxTCB-&amp;gt;xEventListItem ) );&#10; }&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;插入挂起列表项末尾&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;vListInsertEnd( &amp;amp;xSuspendedTaskList, &amp;amp;( pxTCB-&amp;gt;xStateListItem ) );&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果带挂起的任务控制块在等待消息通知，清除消息通知&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;for( x = 0; x &amp;lt; configTASK_NOTIFICATION_ARRAY_ENTRIES; x++ )&#10; {&#10; if( pxTCB-&amp;gt;ucNotifyState[ x ] == taskWAITING_NOTIFICATION )&#10; {&#10; pxTCB-&amp;gt;ucNotifyState[ x ] = taskNOT_WAITING_NOTIFICATION;&#10; }&#10; }&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;判断调度器是否正在运行&lt;/p&gt;&#10;&lt;p&gt;如果正在运行，更新下一个阻塞超时时间&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;if( xSchedulerRunning != pdFALSE )&#10; {&#10; taskENTER_CRITICAL();&#10; {&#10; prvResetNextTaskUnblockTime();&#10; }&#10; taskEXIT_CRITICAL();&#10; }&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;判断挂起是否为任务自己，如果挂起的是自己，强制进行任务切换。&lt;/p&gt;&#10;&lt;p&gt;如果不是，判断当前挂起的任务总数等于创建的任务总数，表明全部在挂起，则将任务控制块赋值为NULL，&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;if( pxTCB == pxCurrentTCB )&#10; {&#10; if( xSchedulerRunning != pdFALSE )&#10; {&#10; configASSERT( uxSchedulerSuspended == 0 );&#10; portYIELD_WITHIN_API();&#10; }&#10; else&#10; {&#10; if( listCURRENT_LIST_LENGTH( &amp;amp;xSuspendedTaskList ) == uxCurrentNumberOfTasks ) &#10; {&#10; pxCurrentTCB = NULL;&#10; }&#10; else&#10; {&#10; vTaskSwitchContext();&#9;&#9;//查找下一个最高优先级任务&#10; }&#10; }&#10; }&#10;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="任务恢复"&gt;&lt;a href="#%e4%bb%bb%e5%8a%a1%e6%81%a2%e5%a4%8d" class="header-anchor"&gt;&lt;/a&gt;任务恢复&#13;&#10;&lt;/h2&gt;&lt;p&gt;任务句柄赋值给任务控制块&lt;/p&gt;&#10;&lt;p&gt;TCB_t * const pxTCB = xTaskToResume;&lt;/p&gt;&#10;&lt;p&gt;恢复的任务控制块不能等于当前任务和NULL&lt;/p&gt;&#10;&lt;p&gt;if( ( pxTCB != pxCurrentTCB ) &amp;amp;&amp;amp; ( pxTCB != NULL ) )&lt;/p&gt;&#10;&lt;p&gt;如果成立进入，判断任务控制块是否在挂起列表中&lt;/p&gt;&#10;&lt;p&gt;if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE )&lt;/p&gt;&#10;&lt;p&gt;如果成立进入，在挂起列表中移除&lt;/p&gt;&#10;&lt;p&gt;( void ) uxListRemove( &amp;amp;( pxTCB-&amp;gt;xStateListItem ) );&lt;/p&gt;&#10;&lt;p&gt;并添加到就绪列表&lt;/p&gt;&#10;&lt;p&gt;prvAddTaskToReadyList( pxTCB );&lt;/p&gt;&#10;&lt;p&gt;在判断优先级是否大于当前优先级，如果是，则任务切换&lt;/p&gt;&#10;&lt;p&gt;taskYIELD_IF_USING_PREEMPTION();&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt; if( ( pxTCB != pxCurrentTCB ) &amp;amp;&amp;amp; ( pxTCB != NULL ) )&#10; {&#10; taskENTER_CRITICAL();&#10; {&#10; if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE )&#10; {&#10; traceTASK_RESUME( pxTCB );&#10; ( void ) uxListRemove( &amp;amp;( pxTCB-&amp;gt;xStateListItem ) );&#10; prvAddTaskToReadyList( pxTCB );&#10; if( pxTCB-&amp;gt;uxPriority &amp;gt;= pxCurrentTCB-&amp;gt;uxPriority )&#10; {&#10; taskYIELD_IF_USING_PREEMPTION();&#10; }&#10; else&#10; {&#10; mtCOVERAGE_TEST_MARKER();&#10; }&#10; }&#10; else&#10; {&#10; mtCOVERAGE_TEST_MARKER();&#10; }&#10; }&#10; taskEXIT_CRITICAL();&#10; }&#10; else&#10; {&#10; mtCOVERAGE_TEST_MARKER();&#10; }&#10;&lt;/code&gt;&lt;/pre&gt;&lt;h1 id="3临界段代码保护"&gt;&lt;a href="#3%e4%b8%b4%e7%95%8c%e6%ae%b5%e4%bb%a3%e7%a0%81%e4%bf%9d%e6%8a%a4" class="header-anchor"&gt;&lt;/a&gt;3.临界段代码保护&#13;&#10;&lt;/h1&gt;&lt;p&gt;通过++，&amp;ndash;实现了嵌套，本质还是基于portDISABLE_INTERRUPTS();和portENABLE_INTERRUPTS();&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;/*进入临界段*/&#10;#define taskENTER_CRITICAL() portENTER_CRITICAL()&#10;#define portENTER_CRITICAL() vPortEnterCritical()&#10;&#10;void vPortEnterCritical( void )&#10;{&#10; portDISABLE_INTERRUPTS();&#10; uxCriticalNesting++;&#10; if( uxCriticalNesting == 1 )&#10; {&#10; configASSERT( ( portNVIC_INT_CTRL_REG &amp;amp; portVECTACTIVE_MASK ) == 0 );&#10; }&#10;}&#10;&#10;/*退出临界段*/&#10;void vPortExitCritical( void )&#10;{&#10; configASSERT( uxCriticalNesting );&#10; uxCriticalNesting--;&#10; if( uxCriticalNesting == 0 )&#10; {&#10; portENABLE_INTERRUPTS();&#10; }&#10;}&#10;&lt;/code&gt;&lt;/pre&gt;&lt;h1 id="4任务调度"&gt;&lt;a href="#4%e4%bb%bb%e5%8a%a1%e8%b0%83%e5%ba%a6" class="header-anchor"&gt;&lt;/a&gt;4.任务调度&#13;&#10;&lt;/h1&gt;</description></item><item><title>FreeRTOS 常用 API 手册</title><link>https://zeseanblog.top/p/freertos-api/</link><pubDate>Sat, 26 Jul 2025 10:30:00 +0800</pubDate><guid>https://zeseanblog.top/p/freertos-api/</guid><description>&lt;h1 id="任务内核"&gt;&lt;a href="#%e4%bb%bb%e5%8a%a1%e5%86%85%e6%a0%b8" class="header-anchor"&gt;&lt;/a&gt;任务内核&#13;&#10;&lt;/h1&gt;&lt;h2 id="portdisable_interrupts-portenable_interrupts"&gt;&lt;a href="#portdisable_interrupts-portenable_interrupts" class="header-anchor"&gt;&lt;/a&gt;portDISABLE_INTERRUPTS() portENABLE_INTERRUPTS()&#13;&#10;&lt;/h2&gt;&lt;p&gt;关闭FreeRTOS可管理的5-15优先级的中断&lt;/p&gt;&#10;&lt;p&gt;开启FreeRTOS可管理的5-15优先级的中断&lt;/p&gt;&#10;&lt;h2 id="taskenter_critical-taskexit_critical"&gt;&lt;a href="#taskenter_critical-taskexit_critical" class="header-anchor"&gt;&lt;/a&gt;taskENTER_CRITICAL() taskEXIT_CRITICAL()&#13;&#10;&lt;/h2&gt;&lt;p&gt;任务中进入临界段&lt;/p&gt;&#10;&lt;p&gt;任务中退出临界段&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;taskENTER_CRITICAL() ;&#10;{&#10;… … /* 临界区 */&#10;}&#10;taskEXIT_CRITICAL() ;&#10;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="taskenter_critical_from_isr-taskexit_critical_from_isr"&gt;&lt;a href="#taskenter_critical_from_isr-taskexit_critical_from_isr" class="header-anchor"&gt;&lt;/a&gt;taskENTER_CRITICAL_FROM_ISR() taskEXIT_CRITICAL_FROM_ISR()&#13;&#10;&lt;/h2&gt;&lt;p&gt;中断中进入临界段&lt;/p&gt;&#10;&lt;p&gt;中断中退出临界段&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;uint32_t save_status;&#10;save_status = taskENTER_CRITICAL_FROM_ISR() ；&#10;{&#10;… … /* 临界区 */&#10;}&#10;taskEXIT_CRITICAL_FROM_ISR(save_status );&#10;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="vtasksuspendall-xtaskresumeall"&gt;&lt;a href="#vtasksuspendall-xtaskresumeall" class="header-anchor"&gt;&lt;/a&gt;vTaskSuspendAll() xTaskResumeAll()&#13;&#10;&lt;/h2&gt;&lt;p&gt;实现任务调度器挂起与恢复&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;vTaskSuspendAll() ;&#10;{&#10;… … /* 内容 */&#10;}&#10;xTaskResumeAll();&#10;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="void-vtaskstartscheduler"&gt;&lt;a href="#void-vtaskstartscheduler" class="header-anchor"&gt;&lt;/a&gt;void vTaskStartScheduler()&#13;&#10;&lt;/h2&gt;&lt;p&gt;vTaskStartScheduler();&lt;/p&gt;&#10;&lt;h1 id="任务创建与删除"&gt;&lt;a href="#%e4%bb%bb%e5%8a%a1%e5%88%9b%e5%bb%ba%e4%b8%8e%e5%88%a0%e9%99%a4" class="header-anchor"&gt;&lt;/a&gt;任务创建与删除&#13;&#10;&lt;/h1&gt;&lt;h2 id="1xtaskcreate"&gt;&lt;a href="#1xtaskcreate" class="header-anchor"&gt;&lt;/a&gt;1.xTaskCreate&#13;&#10;&lt;/h2&gt;&lt;h3 id="参数和返回值"&gt;&lt;a href="#%e5%8f%82%e6%95%b0%e5%92%8c%e8%bf%94%e5%9b%9e%e5%80%bc" class="header-anchor"&gt;&lt;/a&gt;参数和返回值&#13;&#10;&lt;/h3&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;BaseType_t xTaskCreate&#10;(&#10;&#9;TaskFunction_t pxTaskCode, &#9;&#9;&#9;&#9;&#9;/* 指向任务函数的指针 */&#10;&#9;const char * const pcName, &#9;&#9;&#9;&#9;&#9;/* 任务名字，最大长度 configMAX_TASK_NAME_LEN */&#10;&#9;const configSTACK_DEPTH_TYPE usStackDepth, &#9;/* 任务堆栈大小，注意字为单位 */&#10;&#9;void * const pvParameters, &#9;&#9;&#9;&#9;&#9;/* 传递给任务函数的参数 */&#10;&#9;UBaseType_t uxPriority, &#9;&#9;&#9;&#9;&#9;/* 任务优先级，范围： 0 ~ configMAX_PRIORITIES - 1 */&#10;&#9;TaskHandle_t * const pxCreatedTask &#9;&#9;&#9;/* 任务句柄，就是任务的任务控制块 */&#10;)&#10;&#10;返回:&#10;pdPASS 任务创建成功&#10;errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY 任务创建失败&#10;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="实现例程"&gt;&lt;a href="#%e5%ae%9e%e7%8e%b0%e4%be%8b%e7%a8%8b" class="header-anchor"&gt;&lt;/a&gt;实现例程&#13;&#10;&lt;/h3&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;#define START_TASK_STACK_SIZE &#9;128&#9;&#9;&#9;&#9;&#9;//栈大小&#10;#define START_TASK_PRIO &#9; &#9;1&#9;&#9;&#9;&#9;&#9;//优先级&#10;TaskHandle_t &#9;&#9;&#9;&#9;&#9;start_task_handle;&#9;//句柄&#10;void startTask(void* pvParamenters);&#10;&#10;#define TASK1_STACK_SIZE &#9;&#9;128&#10;#define TASK1_PRIO &#9; &#9;&#9;&#9;2&#10;TaskHandle_t &#9;&#9;&#9;&#9;&#9;task1_handle;&#10;void task1(void* pvParamenters);&#10;&#10;void freertos_demo(void)&#10;{&#10;&#9;xTaskCreate( (TaskFunction_t&#9; ) startTask,&#10;&#9; &#9;&#9;&#9; (char *&#9;&#9; ) &amp;#34;startTask&amp;#34;, &#10;&#9;&#9;&#9;&#9; (configSTACK_DEPTH_TYPE) START_TASK_STACK_SIZE,&#10;&#9;&#9;&#9;&#9; (void * &#9;&#9;&#9; ) NULL,&#10;&#9;&#9;&#9;&#9; (UBaseType_t ) START_TASK_PRIO,&#10;&#9;&#9;&#9;&#9; (TaskHandle_t * &#9; ) &amp;amp;start_task_handle );&#10;&#10;&#9;vTaskStartScheduler();&#10;}&#10;&#10;void startTask(void* pvParamenters)&#10;{&#10;&#9;taskENTER_CRITICAL();&#10;&#9;xTaskCreate( (TaskFunction_t &#9; ) task1,&#9;&#9;&#9;//任务函数&#10;&#9;&#9;&#9;&#9; (char *&#9;&#9; &#9; ) &amp;#34;task1&amp;#34;, &#9;&#9;&#9;//任务名&#10;&#9;&#9;&#9; &#9; (configSTACK_DEPTH_TYPE) TASK1_STACK_SIZE,&#9;//任务堆栈&#10;&#9;&#9;&#9;&#9; (void * &#9;&#9; &#9; ) NULL,&#9;&#9;&#9;&#9;//任务函数参数&#10;&#9;&#9;&#9;&#9; (UBaseType_t ) TASK1_PRIO,&#9;&#9;//优先级&#10;&#9;&#9;&#9;&#9; (TaskHandle_t * &#9; ) &amp;amp;task1_handle );&#9;//任务句柄（就是指向任务控制块头的指针）&#10;&#10;&#9;vTaskDelete(start_task_handle);&#10;&#9;taskEXIT_CRITICAL();&#10;}&#10;&#10;void task1(void* pvParamenters){&#10;&#9;while(1){&#10;&#9;}&#10;}&#10;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="2xtaskcreatestatic"&gt;&lt;a href="#2xtaskcreatestatic" class="header-anchor"&gt;&lt;/a&gt;2.xTaskCreateStatic&#13;&#10;&lt;/h2&gt;&lt;h3 id="参数和返回值-1"&gt;&lt;a href="#%e5%8f%82%e6%95%b0%e5%92%8c%e8%bf%94%e5%9b%9e%e5%80%bc-1" class="header-anchor"&gt;&lt;/a&gt;参数和返回值&#13;&#10;&lt;/h3&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;TaskHandle_t xTaskCreateStatic&#10;(&#10;&#9;TaskFunction_t pxTaskCode, &#9;&#9;&#9;/* 指向任务函数的指针 */&#10;&#9;const char * const pcName, &#9;&#9;&#9;/* 任务函数名 */&#10;&#9;const uint32_t ulStackDepth, &#9;&#9;/* 任务堆栈大小注意字为单位 */&#10;&#9;void * const pvParameters, &#9;&#9;&#9;/* 传递的任务函数参数 */&#10;&#9;UBaseType_t uxPriority, &#9;&#9;&#9;/* 任务优先级 */&#10;&#9;StackType_t * const puxStackBuffer, /* 任务堆栈，一般为数组，由用户分配 */&#10;&#9;StaticTask_t * const pxTaskBuffer &#9;/* 任务控制块指针，由用户分配 */&#10;);&#10;&#10;返回:&#10;NULL 用户没有提供相应的内存，任务创建失败&#10;其他值 任务句柄，任务创建成功&#10;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="实现例程-1"&gt;&lt;a href="#%e5%ae%9e%e7%8e%b0%e4%be%8b%e7%a8%8b-1" class="header-anchor"&gt;&lt;/a&gt;实现例程&#13;&#10;&lt;/h3&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;#define START_TASK_STACK_SIZE &#9;128&#10;#define START_TASK_PRIO &#9; &#9;1&#10;TaskHandle_t &#9;&#9;&#9;&#9;&#9;start_task_handle;&#10;StackType_t&#9;&#9;&#9;&#9;&#9;&#9;start_task_stack[START_TASK_STACK_SIZE];&#10;StaticTask_t&#9;&#9;&#9;&#9;&#9;start_task_buffer;&#10;void startTask(void* pvParamenters);&#10;&#10;#define TASK1_STACK_SIZE &#9;&#9;128&#10;#define TASK1_PRIO &#9; &#9;&#9;&#9;2&#10;TaskHandle_t &#9;&#9;&#9;&#9;&#9;task1_handle;&#10;StackType_t&#9;&#9;&#9;&#9;&#9;&#9;task1_stack[TASK1_STACK_SIZE];&#10;StaticTask_t&#9;&#9;&#9;&#9;&#9;task1_buffer;&#10;void task1(void* pvParamenters);&#10;&#10;/*空闲任务配置*/&#10;StaticTask_t idle_task_tcb;&#10;StackType_t idle_task_stack[configMINIMAL_STACK_SIZE];&#10;&#10;/*软件定时器任务配置*/&#10;StaticTask_t timer_task_tcb;&#10;StackType_t timer_task_stack[configTIMER_TASK_STACK_DEPTH];&#10;&#10;/*空闲任务内存分配*/&#10;void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,&#10; StackType_t ** ppxIdleTaskStackBuffer,&#10; uint32_t * pulIdleTaskStackSize )&#10;{&#10;&#9;*ppxIdleTaskTCBBuffer = &amp;amp;idle_task_tcb;&#10;&#9;*ppxIdleTaskStackBuffer = idle_task_stack;&#10;&#9;*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;&#10;}&#10;&#10;/*软件定时器内存分配*/&#10;void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer,&#10; StackType_t ** ppxTimerTaskStackBuffer,&#10; uint32_t * pulTimerTaskStackSize )&#10;{&#10;&#9;*ppxTimerTaskTCBBuffer = &amp;amp;timer_task_tcb;&#10;&#9;*ppxTimerTaskStackBuffer = timer_task_stack;&#10;&#9;*pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;&#10;}&#10;&#10;void freertos_demo(void)&#10;{&#10;&#9;&#10;&#9;start_task_handle = xTaskCreateStatic( (TaskFunction_t) startTask,&#10;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9; (char* &#9;&#9; ) &amp;#34;startTask&amp;#34;, &#10;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9; (uint32_t&#9; ) START_TASK_STACK_SIZE,&#10;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9; (void*&#9;&#9; ) NULL,&#10;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9; (UBaseType_t&#9; ) START_TASK_PRIO,&#10;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9; (StackType_t* ) start_task_stack,&#10;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9; (StaticTask_t* ) &amp;amp;start_task_buffer );&#10;&#9;vTaskStartScheduler();&#10;}&#10;&#10;void startTask(void* pvParamenters)&#10;{&#10;&#9;taskENTER_CRITICAL();&#10;&#9;task1_handle = xTaskCreateStatic( (TaskFunction_t) task1,&#10;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9; (char* &#9;&#9; ) &amp;#34;task1&amp;#34;, &#10;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9; (uint32_t&#9; ) TASK1_STACK_SIZE,&#10;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9; (void*&#9;&#9; ) NULL,&#10;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9; (UBaseType_t&#9; ) TASK1_PRIO,&#10;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9; (StackType_t* ) task1_stack,&#10;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9; (StaticTask_t* ) &amp;amp;task1_buffer );&#10;&#9;vTaskDelete(start_task_handle);&#10;&#9;taskEXIT_CRITICAL();&#10;}&#10;&#10;void task1(void* pvParamenters)&#10;{&#10;&#9;while(1)&#10;&#9;{&#10;&#9;}&#10;}&#10;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="3vtaskdelete"&gt;&lt;a href="#3vtaskdelete" class="header-anchor"&gt;&lt;/a&gt;3.vTaskDelete&#13;&#10;&lt;/h2&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;void vTaskDelete(TaskHandle_t xTaskToDelete);//xTaskToDelete 待删除任务的任务句柄&#10;&lt;/code&gt;&lt;/pre&gt;&lt;h1 id="任务挂起与恢复"&gt;&lt;a href="#%e4%bb%bb%e5%8a%a1%e6%8c%82%e8%b5%b7%e4%b8%8e%e6%81%a2%e5%a4%8d" class="header-anchor"&gt;&lt;/a&gt;任务挂起与恢复&#13;&#10;&lt;/h1&gt;&lt;h2 id="1vtasksuspend"&gt;&lt;a href="#1vtasksuspend" class="header-anchor"&gt;&lt;/a&gt;1.vTaskSuspend&#13;&#10;&lt;/h2&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;void vTaskSuspend( TaskHandle_t xTaskToSuspend );&#10;vTaskSuspend(任务句柄);&#10;vTaskSuspend(NULL);//挂起本任务&#10;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="2vtaskresume"&gt;&lt;a href="#2vtaskresume" class="header-anchor"&gt;&lt;/a&gt;2.vTaskResume&#13;&#10;&lt;/h2&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;void vTaskResume( TaskHandle_t xTaskToResume );&#10;vTaskResume(任务句柄);&#10;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="3xtaskresumefromisr"&gt;&lt;a href="#3xtaskresumefromisr" class="header-anchor"&gt;&lt;/a&gt;3.xTaskResumeFromISR&#13;&#10;&lt;/h2&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume );&#10;&#10;void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)&#10;{&#10;&#9;BaseType_t xYieldRequired;&#10;&#9;switch(GPIO_Pin)&#10;&#9;{&#10;&#9;case GPIO_PIN_0:&#10;&#9;&#9;delay_ms(20); /* 消抖 */&#10;&#9;&#9;flag2_suspend++;&#10;&#9;&#9;if(flag2_suspend%2==1) vTaskSuspend(task2_handle);&#10;&#9;&#9;else xYieldRequired = xTaskResumeFromISR(task2_handle);&#10;&#9;&#9;portYIELD_FROM_ISR( xYieldRequired );&#9;&#9;//任务恢复后需要进行任务切换&#10;&#9;&#9;&#10;&#9;&#9;break;&#10;&#9;}&#10;}&#10;&lt;/code&gt;&lt;/pre&gt;&lt;h1 id="列表与列表项"&gt;&lt;a href="#%e5%88%97%e8%a1%a8%e4%b8%8e%e5%88%97%e8%a1%a8%e9%a1%b9" class="header-anchor"&gt;&lt;/a&gt;列表与列表项&#13;&#10;&lt;/h1&gt;&lt;h2 id="1vlistinitialise"&gt;&lt;a href="#1vlistinitialise" class="header-anchor"&gt;&lt;/a&gt;1.vListInitialise&#13;&#10;&lt;/h2&gt;&lt;p&gt;初始化列表&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;span class="lnt"&gt;15&#10;&lt;/span&gt;&lt;span class="lnt"&gt;16&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/*pxList 是待初始化列表*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;vListInitialise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;List_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;pxList&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;//初始化时，列表只有xListEnd，pxIndex指向xListEnd&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;pxList&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;pxIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;ListItem_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;pxList&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;xListEnd&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//末尾列表项默认最大值，升序排序在最后&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;pxList&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;xListEnd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xItemValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;portMAX_DELAY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//初始化时，列表中只有xListEnd，因此上下都是本身&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;pxList&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;xListEnd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pxNext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;ListItem_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;pxList&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;xListEnd&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;pxList&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;xListEnd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pxPrevious&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;ListItem_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;pxList&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;xListEnd&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//初始化时列表项数量为0（不包含xListEnd）&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;pxList&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;uxNumberOfItems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;UBaseType_t&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mi"&gt;0U&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//初始化校验&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="nf"&gt;listSET_LIST_INTEGRITY_CHECK_1_VALUE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;pxList&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="nf"&gt;listSET_LIST_INTEGRITY_CHECK_2_VALUE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;pxList&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h2 id="2vlistinitialiseitem"&gt;&lt;a href="#2vlistinitialiseitem" class="header-anchor"&gt;&lt;/a&gt;2.vListInitialiseItem&#13;&#10;&lt;/h2&gt;&lt;p&gt;初始化列表项&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;span class="lnt"&gt;7&#10;&lt;/span&gt;&lt;span class="lnt"&gt;8&#10;&lt;/span&gt;&lt;span class="lnt"&gt;9&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/*pxItem是待初始化列表项*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;vListInitialiseItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;ListItem_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;pxItem&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//初始化时，列表项所在列表为空&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;pxItem&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;pxContainer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;pxItem&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;pxItem&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h2 id="3vlistinsertend"&gt;&lt;a href="#3vlistinsertend" class="header-anchor"&gt;&lt;/a&gt;3.vListInsertEnd&#13;&#10;&lt;/h2&gt;&lt;p&gt;列表末尾插入列表项&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;//目标列表，目标列表项&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;vListInsertEnd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;List_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;pxList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;ListItem_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;pxNewListItem&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h2 id="4vlistinsert"&gt;&lt;a href="#4vlistinsert" class="header-anchor"&gt;&lt;/a&gt;4.vListInsert&#13;&#10;&lt;/h2&gt;&lt;p&gt;列表插入列表项&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;//目标列表，目标列表项&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;vListInsert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;List_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;pxList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;ListItem_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;pxNewListItem&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h2 id="5uxlistremove"&gt;&lt;a href="#5uxlistremove" class="header-anchor"&gt;&lt;/a&gt;5.uxListRemove&#13;&#10;&lt;/h2&gt;&lt;p&gt;列表移除列表项&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;//pxItemToRemove 待移除的列表项&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;UBaseType_t&lt;/span&gt; &lt;span class="nf"&gt;uxListRemove&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;ListItem_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;pxItemToRemove&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;//返回值，移除后所剩列表项&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h2 id="插入删除实验"&gt;&lt;a href="#%e6%8f%92%e5%85%a5%e5%88%a0%e9%99%a4%e5%ae%9e%e9%aa%8c" class="header-anchor"&gt;&lt;/a&gt;插入删除实验&#13;&#10;&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/*创建列表*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;List_t&lt;/span&gt; &#9; &lt;span class="n"&gt;TestList&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;ListItem_t&lt;/span&gt; &lt;span class="n"&gt;ListItem1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/*初始化列表，列表项*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;vListInitialise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;TestList&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;vListInitialiseItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ListItem1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;ListItem1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xItemValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/*插入列表项*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;vListInsert&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;List_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;TestList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="cm"&gt;/* 列表 */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ListItem_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ListItem1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="cm"&gt;/* 列表项 */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h1 id="任务相关api"&gt;&lt;a href="#%e4%bb%bb%e5%8a%a1%e7%9b%b8%e5%85%b3api" class="header-anchor"&gt;&lt;/a&gt;任务相关API&#13;&#10;&lt;/h1&gt;&lt;p&gt;&lt;img alt="image-20250805151211347" class="gallery-image" data-flex-basis="376px" data-flex-grow="156" height="693" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos-api/images/image-20250805151211347.png" srcset="https://zeseanblog.top/p/freertos-api/images/image-20250805151211347_hu_e2de76a4f0a3fb67.png 800w, https://zeseanblog.top/p/freertos-api/images/image-20250805151211347.png 1086w" width="1086"&gt;&lt;/p&gt;&#10;&lt;h2 id="1uxtaskpriorityget"&gt;&lt;a href="#1uxtaskpriorityget" class="header-anchor"&gt;&lt;/a&gt;1.uxTaskPriorityGet&#13;&#10;&lt;/h2&gt;&lt;p&gt;获取任务优先级&lt;/p&gt;&#10;&lt;p&gt;打开宏INCLUDE_uxTaskPriorityGet&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;//xTask要查找的任务句柄， NULL 代表任务自身&#10;UBaseType_t uxTaskPriorityGet( const TaskHandle_t xTask )&#10;//返回无符号整数，为任务优先级&#10;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="2vtaskpriorityset"&gt;&lt;a href="#2vtaskpriorityset" class="header-anchor"&gt;&lt;/a&gt;2.vTaskPrioritySet&#13;&#10;&lt;/h2&gt;&lt;p&gt;改变任务优先级&lt;/p&gt;&#10;&lt;p&gt;宏 INCLUDE_vTaskPrioritySet 为 1&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;//xTask任务句柄 uxNewPriority优先级&#10;void vTaskPrioritySet( TaskHandle_t xTask , UBaseType_t uxNewPriority )&#10;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="3uxtaskgetnumberoftasks"&gt;&lt;a href="#3uxtaskgetnumberoftasks" class="header-anchor"&gt;&lt;/a&gt;3.uxTaskGetNumberOfTasks&#13;&#10;&lt;/h2&gt;&lt;p&gt;此函数用于获取系统中任务的任务数量&lt;/p&gt;&#10;&lt;p&gt;UBaseType_t uxTaskGetNumberOfTasks( void )&lt;/p&gt;&#10;&lt;h2 id="4uxtaskgetsystemstate"&gt;&lt;a href="#4uxtaskgetsystemstate" class="header-anchor"&gt;&lt;/a&gt;4.uxTaskGetSystemState&#13;&#10;&lt;/h2&gt;&lt;p&gt;获取系统中所有任务的任务状态信息&lt;/p&gt;&#10;&lt;h1 id="消息队列api"&gt;&lt;a href="#%e6%b6%88%e6%81%af%e9%98%9f%e5%88%97api" class="header-anchor"&gt;&lt;/a&gt;消息队列API&#13;&#10;&lt;/h1&gt;&lt;p&gt;例子&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;span class="lnt"&gt;15&#10;&lt;/span&gt;&lt;span class="lnt"&gt;16&#10;&lt;/span&gt;&lt;span class="lnt"&gt;17&#10;&lt;/span&gt;&lt;span class="lnt"&gt;18&#10;&lt;/span&gt;&lt;span class="lnt"&gt;19&#10;&lt;/span&gt;&lt;span class="lnt"&gt;20&#10;&lt;/span&gt;&lt;span class="lnt"&gt;21&#10;&lt;/span&gt;&lt;span class="lnt"&gt;22&#10;&lt;/span&gt;&lt;span class="lnt"&gt;23&#10;&lt;/span&gt;&lt;span class="lnt"&gt;24&#10;&lt;/span&gt;&lt;span class="lnt"&gt;25&#10;&lt;/span&gt;&lt;span class="lnt"&gt;26&#10;&lt;/span&gt;&lt;span class="lnt"&gt;27&#10;&lt;/span&gt;&lt;span class="lnt"&gt;28&#10;&lt;/span&gt;&lt;span class="lnt"&gt;29&#10;&lt;/span&gt;&lt;span class="lnt"&gt;30&#10;&lt;/span&gt;&lt;span class="lnt"&gt;31&#10;&lt;/span&gt;&lt;span class="lnt"&gt;32&#10;&lt;/span&gt;&lt;span class="lnt"&gt;33&#10;&lt;/span&gt;&lt;span class="lnt"&gt;34&#10;&lt;/span&gt;&lt;span class="lnt"&gt;35&#10;&lt;/span&gt;&lt;span class="lnt"&gt;36&#10;&lt;/span&gt;&lt;span class="lnt"&gt;37&#10;&lt;/span&gt;&lt;span class="lnt"&gt;38&#10;&lt;/span&gt;&lt;span class="lnt"&gt;39&#10;&lt;/span&gt;&lt;span class="lnt"&gt;40&#10;&lt;/span&gt;&lt;span class="lnt"&gt;41&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;QueueHandle_t&lt;/span&gt; &lt;span class="n"&gt;key_quque&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/*小数据句柄*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;QueueHandle_t&lt;/span&gt; &lt;span class="n"&gt;big_date_queue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="cm"&gt;/*大数据句柄*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;buff&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;This is a big data queue&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;key_quque&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;xQueueCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key_quque&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;key_queue队列创建成功&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;key_queue队列创建失败&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;big_date_queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;xQueueCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key_quque&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;big_date_queue队列创建成功&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;big_date_queue队列创建失败&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/*入队，发送*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;task1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;key_val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;key_scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key_val&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;KEY0_PRES&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;key_val&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;KEY1_PRES&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;xQueueSend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key_quque&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;key_val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;portMAX_DELAY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="n"&gt;pdTRUE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;key_queue队列发送失败&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/*出队，读取*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;task2&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;xQueueReceive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;big_date_queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;portMAX_DELAY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="n"&gt;pdTRUE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;big_date_queue队列接收失败&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;big_date_queue读取队列成功,数据%s&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;</description></item><item><title>FreeRTOS 学习笔记：从入门到内核机制</title><link>https://zeseanblog.top/p/freertos/</link><pubDate>Sat, 12 Jul 2025 10:00:00 +0800</pubDate><guid>https://zeseanblog.top/p/freertos/</guid><description>&lt;h1 id="序freertos函数名前缀"&gt;&lt;a href="#%e5%ba%8ffreertos%e5%87%bd%e6%95%b0%e5%90%8d%e5%89%8d%e7%bc%80" class="header-anchor"&gt;&lt;/a&gt;序、FreeRTOS函数名前缀&#13;&#10;&lt;/h1&gt;&lt;img src="images/image-20250804213757624.png" alt="image-20250804213757624" style="zoom:67%;" /&gt;&#10;&lt;h1 id="一单片机程序设计模式"&gt;&lt;a href="#%e4%b8%80%e5%8d%95%e7%89%87%e6%9c%ba%e7%a8%8b%e5%ba%8f%e8%ae%be%e8%ae%a1%e6%a8%a1%e5%bc%8f" class="header-anchor"&gt;&lt;/a&gt;一、单片机程序设计模式&#13;&#10;&lt;/h1&gt;&lt;p&gt;&lt;strong&gt;1.轮询模式&lt;/strong&gt;&lt;/p&gt;&#10; &lt;img src="images/image-20250802143036241.png" alt="image-20250802143036241" style="zoom: 50%;" /&gt;&#10;&lt;p&gt;&lt;strong&gt;2.前后台&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;后台：执行在main&lt;/p&gt;&#10;&lt;p&gt;前台：执行在中断，但不能执行太多&lt;/p&gt;&#10;&lt;p&gt;可以在中断中用标志位，将任务放在主函数&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;3.定时器驱动&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;函数执行不能太长&lt;/p&gt;&#10; &lt;img src="images/image-20250802143221867.png" alt="image-20250802143221867" style="zoom:50%;" /&gt;&#10;&lt;p&gt;&lt;strong&gt;4.状态机&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;基于轮询，将单个任务分解成多个任务，减少每个任务需要的时间，降低造成的相互影响&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;5.多任务系统&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;交替执行，基于时间片和任务优先级调度&lt;/p&gt;&#10;&lt;p&gt;对于重要的任务可以提高优先级，在高优先级处于延时中执行低优先级任务&lt;/p&gt;&#10; &lt;img src="images/image-20250802144931000.png" alt="image-20250802144931000" style="zoom:50%;" /&gt;&#10;&lt;p&gt;&lt;img alt="image-20250802143633146" class="gallery-image" data-flex-basis="1053px" data-flex-grow="439" height="202" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250802143633146.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250802143633146_hu_57a937242619cb17.png 800w, https://zeseanblog.top/p/freertos/images/image-20250802143633146.png 887w" width="887"&gt;&lt;/p&gt;&#10;&lt;p&gt;伪代码实现&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;void main()&#10;{&#10;// 创建 2 个任务&#10;create_task(task1);&#10;create_task(task2);&#10;// 启动调度器&#10;start_scheduler();&#10;}&#10;task1()&#10;{&#10;while(1)&#10;{&#10;&#9;do_task1();&#10;}&#10;}&#10;task2()&#10;{&#10;while(1)&#10;{&#10;&#9;do_task2();&#10;}&#10;}&#10;&lt;/code&gt;&lt;/pre&gt;&lt;h1 id="二freertos基础知识"&gt;&lt;a href="#%e4%ba%8cfreertos%e5%9f%ba%e7%a1%80%e7%9f%a5%e8%af%86" class="header-anchor"&gt;&lt;/a&gt;二、FreeRTOS基础知识&#13;&#10;&lt;/h1&gt;&lt;h2 id="1任务调度简介熟悉"&gt;&lt;a href="#1%e4%bb%bb%e5%8a%a1%e8%b0%83%e5%ba%a6%e7%ae%80%e4%bb%8b%e7%86%9f%e6%82%89" class="header-anchor"&gt;&lt;/a&gt;1.任务调度简介(熟悉)&#13;&#10;&lt;/h2&gt;&lt;h5 id="抢占式每个任务有优先级优先级高抢占优先级低"&gt;&lt;a href="#%e6%8a%a2%e5%8d%a0%e5%bc%8f%e6%af%8f%e4%b8%aa%e4%bb%bb%e5%8a%a1%e6%9c%89%e4%bc%98%e5%85%88%e7%ba%a7%e4%bc%98%e5%85%88%e7%ba%a7%e9%ab%98%e6%8a%a2%e5%8d%a0%e4%bc%98%e5%85%88%e7%ba%a7%e4%bd%8e" class="header-anchor"&gt;&lt;/a&gt;抢占式：每个任务有优先级，优先级高抢占优先级低&#13;&#10;&lt;/h5&gt;&lt;p&gt;FreeRTOS数值越大，优先级越高&lt;/p&gt;&#10;&lt;p&gt;Task1 、 Task2 、 Task3 的优先级分别为 1 、 2 、 3 ；在FreeRTOS 中任务设置的数值越大，优先级越高，所以 TASK3 的优先级最高&lt;/p&gt;&#10; &lt;img src="images/image-20250802145631062.png" alt="image-20250802145631062" style="zoom:67%;" /&gt;&#10;&lt;h5 id="时间片同优先级每个时钟节拍切换任务"&gt;&lt;a href="#%e6%97%b6%e9%97%b4%e7%89%87%e5%90%8c%e4%bc%98%e5%85%88%e7%ba%a7%e6%af%8f%e4%b8%aa%e6%97%b6%e9%92%9f%e8%8a%82%e6%8b%8d%e5%88%87%e6%8d%a2%e4%bb%bb%e5%8a%a1" class="header-anchor"&gt;&lt;/a&gt;时间片：同优先级，每个时钟节拍切换任务&#13;&#10;&lt;/h5&gt;&lt;p&gt;同等优先级任务轮流地享有相同的 CPU 时间 ( 可设置 ) ， 叫时间片，在 FreeRTOS 中，一个时间片就等于 SysTick 中断周期&lt;/p&gt;&#10;&lt;p&gt;没用完的时间片抛弃&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250802145838370" class="gallery-image" data-flex-basis="595px" data-flex-grow="248" height="206" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250802145838370.png" width="511"&gt;&lt;/p&gt;&#10;&lt;h5 id="协程式当前执行任务一直执行高优先级不抢占低优先级不常用"&gt;&lt;a href="#%e5%8d%8f%e7%a8%8b%e5%bc%8f%e5%bd%93%e5%89%8d%e6%89%a7%e8%a1%8c%e4%bb%bb%e5%8a%a1%e4%b8%80%e7%9b%b4%e6%89%a7%e8%a1%8c%e9%ab%98%e4%bc%98%e5%85%88%e7%ba%a7%e4%b8%8d%e6%8a%a2%e5%8d%a0%e4%bd%8e%e4%bc%98%e5%85%88%e7%ba%a7%e4%b8%8d%e5%b8%b8%e7%94%a8" class="header-anchor"&gt;&lt;/a&gt;协程式：当前执行任务一直执行，高优先级不抢占低优先级（不常用）&#13;&#10;&lt;/h5&gt;&lt;h2 id="2任务状态熟悉"&gt;&lt;a href="#2%e4%bb%bb%e5%8a%a1%e7%8a%b6%e6%80%81%e7%86%9f%e6%82%89" class="header-anchor"&gt;&lt;/a&gt;2.任务状态(熟悉)&#13;&#10;&lt;/h2&gt;&lt;p&gt;1.运行态&lt;/p&gt;&#10;&lt;p&gt;正在执行，同一时间仅一个&lt;/p&gt;&#10;&lt;p&gt;2.就绪态&lt;/p&gt;&#10;&lt;p&gt;能够被执行，但还未执行&lt;/p&gt;&#10;&lt;p&gt;3.阻塞态&lt;/p&gt;&#10;&lt;p&gt;任务在延时或等待外部事件发生&lt;/p&gt;&#10;&lt;p&gt;4.挂起态&lt;/p&gt;&#10;&lt;p&gt;类似暂停，不参与调度，需要解挂才能进就绪vTaskResume()；&lt;/p&gt;&#10; &lt;img src="images/image-20250802150415156.png" alt="image-20250802150415156" style="zoom: 50%;" /&gt;&#10;&lt;p&gt;注：只有就绪态可以转运行态，挂起要解挂，阻塞要变成就绪&lt;/p&gt;&#10;&lt;h3 id="任务状态列表"&gt;&lt;a href="#%e4%bb%bb%e5%8a%a1%e7%8a%b6%e6%80%81%e5%88%97%e8%a1%a8" class="header-anchor"&gt;&lt;/a&gt;任务状态列表&#13;&#10;&lt;/h3&gt;&lt;p&gt;1.就绪列表：pxReadyTasksLists[x]，其中 x 代表任务优先级数值。0~31，31最高&lt;/p&gt;&#10;&lt;p&gt;32位变量，当某个位置一说明对应优先级有任务存在&lt;/p&gt;&#10; &lt;img src="images/image-20250802151219493.png" alt="image-20250802151219493" style="zoom:60%;" /&gt;&#10;&lt;p&gt;2.阻塞列表：pxDelayedTaskList&lt;/p&gt;&#10;&lt;p&gt;3.挂起列表：xSuspendedTaskList&lt;/p&gt;&#10;&lt;p&gt;调度器取就绪列表最高优先级任务来执行&lt;/p&gt;&#10;&lt;p&gt;相同优先级的任务会连接在同一个就绪列表&lt;/p&gt;&#10;&lt;h1 id="三freertos移植"&gt;&lt;a href="#%e4%b8%89freertos%e7%a7%bb%e6%a4%8d" class="header-anchor"&gt;&lt;/a&gt;三、FreeRTOS移植&#13;&#10;&lt;/h1&gt;&lt;p&gt;源码：https://www.freertos.org/&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250802152204321" class="gallery-image" data-flex-basis="195px" data-flex-grow="81" height="365" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250802152204321.png" width="297"&gt;&lt;/p&gt;&#10;&lt;p&gt;FreeRTOS：内核有用&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250802152338698" class="gallery-image" data-flex-basis="524px" data-flex-grow="218" height="178" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250802152338698.png" width="389"&gt;&lt;/p&gt;&#10;&lt;p&gt;Demo和Source&lt;/p&gt;&#10;&lt;h4 id="source文件夹"&gt;&lt;a href="#source%e6%96%87%e4%bb%b6%e5%a4%b9" class="header-anchor"&gt;&lt;/a&gt;Source文件夹&#13;&#10;&lt;/h4&gt; &lt;img src="images/image-20250802152630841.png" alt="image-20250802152630841" style="zoom:50%;" /&gt;&#10;&lt;p&gt;include,portable,list,queue,task必须&lt;/p&gt;&#10;&lt;h4 id="portable文件夹"&gt;&lt;a href="#portable%e6%96%87%e4%bb%b6%e5%a4%b9" class="header-anchor"&gt;&lt;/a&gt;portable文件夹&#13;&#10;&lt;/h4&gt;&lt;p&gt;与硬件连接桥梁&lt;/p&gt;&#10;&lt;p&gt;由于使用MDK开发，只要&lt;/p&gt;&#10; &lt;img src="images/image-20250802152913833.png" alt="image-20250802152913833" style="zoom:67%;" /&gt;&#10;&lt;h2 id="手把手移植"&gt;&lt;a href="#%e6%89%8b%e6%8a%8a%e6%89%8b%e7%a7%bb%e6%a4%8d" class="header-anchor"&gt;&lt;/a&gt;手把手移植&#13;&#10;&lt;/h2&gt;&lt;p&gt;&lt;img alt="image-20250802153157922" class="gallery-image" data-flex-basis="537px" data-flex-grow="223" height="326" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250802153157922.png" width="730"&gt;&lt;/p&gt;&#10;&lt;p&gt;1.基础工程的Middlewares文件夹中新建一个FreeRTOS子文件夹&lt;/p&gt;&#10; &lt;img src="images/image-20250802153620409.png" alt="image-20250802153620409" style="zoom:50%;" /&gt;&#10;&lt;p&gt;将FreeRTOS内核源码的Source文件夹下的所有文件添加到工程的FreeRTOS文件夹中&lt;/p&gt;&#10; &lt;img src="images/image-20250802153705681.png" alt="image-20250802153705681" style="zoom:67%;" /&gt;&#10;&lt;p&gt;CORE中是源码&lt;/p&gt;&#10;&lt;p&gt;heap_4是内存管理算法4&lt;/p&gt;&#10;&lt;p&gt;port是软硬件连接桥梁&lt;/p&gt;&#10; &lt;img src="images/image-20250802153948337.png" alt="image-20250802153948337" style="zoom:67%;" /&gt;&#10;&lt;p&gt;port根据芯片选择&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250802154239833" class="gallery-image" data-flex-basis="1065px" data-flex-grow="443" height="207" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250802154239833.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250802154239833_hu_c51e4769a0691ebc.png 800w, https://zeseanblog.top/p/freertos/images/image-20250802154239833.png 919w" width="919"&gt;&lt;/p&gt;&#10;&lt;p&gt;头文件哪有就加什么路径&lt;/p&gt;&#10;&lt;p&gt;2.添加 FreeRTOSConfig.h 文件&lt;/p&gt;&#10;&lt;p&gt;这个可裁剪，用不到的功能可以裁剪，Demo里有，或者例程&lt;/p&gt;&#10;&lt;p&gt;3.修改SYSTEM&lt;/p&gt;&#10;&lt;p&gt;详阅《FreeRTOS开发指南》&lt;/p&gt;&#10;&lt;h2 id="系统配置详解"&gt;&lt;a href="#%e7%b3%bb%e7%bb%9f%e9%85%8d%e7%bd%ae%e8%af%a6%e8%a7%a3" class="header-anchor"&gt;&lt;/a&gt;系统配置详解&#13;&#10;&lt;/h2&gt;&lt;p&gt;FreeRTOSConfig.h 配置文件作用：对 FreeRTOS 的功能进行配置和裁剪，以及 API 函数的使能&lt;/p&gt;&#10; &lt;img src="images/image-20250802163812620.png" alt="image-20250802163812620" style="zoom:67%;" /&gt;&#10;&lt;p&gt;详看注释&lt;/p&gt;&#10;&lt;h1 id="四freertos任务创建和删除"&gt;&lt;a href="#%e5%9b%9bfreertos%e4%bb%bb%e5%8a%a1%e5%88%9b%e5%bb%ba%e5%92%8c%e5%88%a0%e9%99%a4" class="header-anchor"&gt;&lt;/a&gt;四、FreeRTOS任务创建和删除&#13;&#10;&lt;/h1&gt;&lt;h2 id="1任务创建和删除的-api-函数"&gt;&lt;a href="#1%e4%bb%bb%e5%8a%a1%e5%88%9b%e5%bb%ba%e5%92%8c%e5%88%a0%e9%99%a4%e7%9a%84-api-%e5%87%bd%e6%95%b0" class="header-anchor"&gt;&lt;/a&gt;1.任务创建和删除的 API 函数&#13;&#10;&lt;/h2&gt;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;API&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;描述&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;xTaskCreate()&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;动态创建&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;xTaskCreateStatic()&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;静态创建&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;vTaskDelete()&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;删除&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;动态创建：任务控制块以及任务栈空间所需内存，有FreeRTOS自动分配&lt;/p&gt;&#10;&lt;p&gt;静态创建：用户分配&lt;/p&gt;&#10;&lt;h3 id="动态创建"&gt;&lt;a href="#%e5%8a%a8%e6%80%81%e5%88%9b%e5%bb%ba" class="header-anchor"&gt;&lt;/a&gt;动态创建&#13;&#10;&lt;/h3&gt;&lt;p&gt;&lt;img alt="image-20250802165520234" class="gallery-image" data-flex-basis="799px" data-flex-grow="333" height="563" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250802165520234.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250802165520234_hu_b794bc9ec6868604.png 800w, https://zeseanblog.top/p/freertos/images/image-20250802165520234_hu_1b5b49cbbc61b1d0.png 1600w, https://zeseanblog.top/p/freertos/images/image-20250802165520234.png 1875w" width="1875"&gt;&lt;/p&gt;&#10;&lt;p&gt;返回pdPass：创建成功&lt;/p&gt;&#10;&lt;p&gt;返回errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY：创建失败&lt;/p&gt;&#10;&lt;h4 id="流程"&gt;&lt;a href="#%e6%b5%81%e7%a8%8b" class="header-anchor"&gt;&lt;/a&gt;流程：&#13;&#10;&lt;/h4&gt;&lt;p&gt;1、将宏 configSUPPORT_DYNAMIC_ALLOCATION 配置为 1&lt;/p&gt;&#10;&lt;p&gt;2 、定义函数入口参数&lt;/p&gt;&#10;&lt;p&gt;3 、编写任务函数&lt;/p&gt;&#10;&lt;p&gt;创建后进入就绪态，然后启动任务调度器运行&lt;/p&gt;&#10;&lt;h4 id="内部实现"&gt;&lt;a href="#%e5%86%85%e9%83%a8%e5%ae%9e%e7%8e%b0" class="header-anchor"&gt;&lt;/a&gt;内部实现：&#13;&#10;&lt;/h4&gt; &lt;img src="images/image-20250802170201003.png" alt="image-20250802170201003" style="zoom:67%;" /&gt;&#10;&lt;p&gt;任务控制块就是任务的身份证，保留任务的信息&lt;/p&gt;&#10;&lt;img src="images/image-20250802170649880.png" alt="image-20250802170649880" style="zoom:50%;" /&gt;&#10;&lt;h3 id="静态创建"&gt;&lt;a href="#%e9%9d%99%e6%80%81%e5%88%9b%e5%bb%ba" class="header-anchor"&gt;&lt;/a&gt;静态创建&#13;&#10;&lt;/h3&gt;&lt;p&gt;&lt;img alt="image-20250802170921182" class="gallery-image" data-flex-basis="647px" data-flex-grow="269" height="362" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250802170921182.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250802170921182_hu_40abea609d88a3e.png 800w, https://zeseanblog.top/p/freertos/images/image-20250802170921182.png 976w" width="976"&gt;&lt;/p&gt;&#10;&lt;p&gt;返回NULL：创建成功&lt;/p&gt;&#10;&lt;p&gt;其他值：任务句柄，任务创建成功&lt;/p&gt;&#10;&lt;h4 id="流程-1"&gt;&lt;a href="#%e6%b5%81%e7%a8%8b-1" class="header-anchor"&gt;&lt;/a&gt;流程：&#13;&#10;&lt;/h4&gt;&lt;p&gt;1 、需将宏 configSUPPORT_STATIC_ALLOCATION 配置为 1&lt;/p&gt;&#10;&lt;p&gt;2 、定义空闲任务 &amp;amp; 定时器任务的任务堆栈及TCB&lt;/p&gt;&#10;&lt;p&gt;3 、实现两个接口函数&lt;/p&gt;&#10;&lt;p&gt;vApplicationGetIdleTaskMemory( )必须&lt;/p&gt;&#10;&lt;p&gt;vApplicationGetTimerTaskMemory ()可选&lt;/p&gt;&#10;&lt;p&gt;4 、定义函数入口参数&lt;/p&gt;&#10;&lt;p&gt;5 、编写任务函数&lt;/p&gt;&#10;&lt;h3 id="任务删除"&gt;&lt;a href="#%e4%bb%bb%e5%8a%a1%e5%88%a0%e9%99%a4" class="header-anchor"&gt;&lt;/a&gt;任务删除&#13;&#10;&lt;/h3&gt;&lt;p&gt;xTaskDelete(TaskHandle_t xTaskToDelete);&lt;/p&gt;&#10;&lt;p&gt;实际是通过传入的任务句柄获取任务控制块，从四个任务列表中移除&lt;/p&gt;&#10;&lt;p&gt;注意：1.当传入NULL，删除任务自身&lt;/p&gt;&#10;&lt;p&gt;​&#9;&#9;&#9;2.空闲任务会释放被删除任务中有系统分配的内存，但是用户在任务&#9;&#9;&#9;&#9;删除前申请的内存，需要手动释放，否则内存泄漏&lt;/p&gt;&#10;&lt;h1 id="五freertos任务挂起与恢复"&gt;&lt;a href="#%e4%ba%94freertos%e4%bb%bb%e5%8a%a1%e6%8c%82%e8%b5%b7%e4%b8%8e%e6%81%a2%e5%a4%8d" class="header-anchor"&gt;&lt;/a&gt;五、FreeRTOS任务挂起与恢复&#13;&#10;&lt;/h1&gt;&lt;h2 id="1任务挂起与恢复的api函数"&gt;&lt;a href="#1%e4%bb%bb%e5%8a%a1%e6%8c%82%e8%b5%b7%e4%b8%8e%e6%81%a2%e5%a4%8d%e7%9a%84api%e5%87%bd%e6%95%b0" class="header-anchor"&gt;&lt;/a&gt;1.任务挂起与恢复的API函数&#13;&#10;&lt;/h2&gt;&lt;p&gt;&lt;img alt="image-20250802212436605" class="gallery-image" data-flex-basis="811px" data-flex-grow="338" height="263" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250802212436605.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250802212436605_hu_8171aa08c628cf52.png 800w, https://zeseanblog.top/p/freertos/images/image-20250802212436605.png 889w" width="889"&gt;&lt;/p&gt;&#10;&lt;p&gt;挂起：暂停&lt;/p&gt;&#10;&lt;p&gt;恢复：继续&lt;/p&gt;&#10;&lt;p&gt;FromISR：从中断中恢复&lt;/p&gt;&#10;&lt;h3 id="任务挂起"&gt;&lt;a href="#%e4%bb%bb%e5%8a%a1%e6%8c%82%e8%b5%b7" class="header-anchor"&gt;&lt;/a&gt;任务挂起&#13;&#10;&lt;/h3&gt;&lt;p&gt;将宏 INCLUDE_vTaskSuspend 配置为 1&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250802212603585" class="gallery-image" data-flex-basis="996px" data-flex-grow="415" height="277" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250802212603585.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250802212603585_hu_26b7ca17e36e60be.png 800w, https://zeseanblog.top/p/freertos/images/image-20250802212603585.png 1150w" width="1150"&gt;&lt;/p&gt;&#10;&lt;h3 id="任务恢复"&gt;&lt;a href="#%e4%bb%bb%e5%8a%a1%e6%81%a2%e5%a4%8d" class="header-anchor"&gt;&lt;/a&gt;任务恢复&#13;&#10;&lt;/h3&gt;&lt;p&gt;将宏 INCLUDE_vTaskSuspend 必须定义为 1&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250802212618152" class="gallery-image" data-flex-basis="1036px" data-flex-grow="431" height="266" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250802212618152.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250802212618152_hu_5d019b8026ccc3bb.png 800w, https://zeseanblog.top/p/freertos/images/image-20250802212618152.png 1149w" width="1149"&gt;&lt;/p&gt;&#10;&lt;h3 id="中断中恢复"&gt;&lt;a href="#%e4%b8%ad%e6%96%ad%e4%b8%ad%e6%81%a2%e5%a4%8d" class="header-anchor"&gt;&lt;/a&gt;中断中恢复&#13;&#10;&lt;/h3&gt;&lt;p&gt;INCLUDE_vTaskSuspend 和 INCLUDE_xTaskResumeFromISR 必须定义为 1&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250802212911425" class="gallery-image" data-flex-basis="830px" data-flex-grow="346" height="405" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250802212911425.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250802212911425_hu_7f879aa76b6f8642.png 800w, https://zeseanblog.top/p/freertos/images/image-20250802212911425.png 1402w" width="1402"&gt;&lt;/p&gt;&#10;&lt;p&gt;注意：中断服务程序中要调用FreeRTOS的API，中断优先级不能高于FreeRTOS所管理的优先级&lt;/p&gt;&#10;&lt;p&gt;因为FreeRTOS管理的5&lt;del&gt;15的优先级，所有中断优先级不能在0&lt;/del&gt;4，因为中断优先级数字越低优先级越高&lt;/p&gt;&#10;&lt;h1 id="六freertos中断管理"&gt;&lt;a href="#%e5%85%adfreertos%e4%b8%ad%e6%96%ad%e7%ae%a1%e7%90%86" class="header-anchor"&gt;&lt;/a&gt;六、FreeRTOS中断管理&#13;&#10;&lt;/h1&gt;&lt;h2 id="1中断"&gt;&lt;a href="#1%e4%b8%ad%e6%96%ad" class="header-anchor"&gt;&lt;/a&gt;1.中断&#13;&#10;&lt;/h2&gt;&lt;p&gt;中断请求，响应中断（转中断处理ISR），退出中断&lt;/p&gt;&#10;&lt;h2 id="2中断优先级"&gt;&lt;a href="#2%e4%b8%ad%e6%96%ad%e4%bc%98%e5%85%88%e7%ba%a7" class="header-anchor"&gt;&lt;/a&gt;2.中断优先级&#13;&#10;&lt;/h2&gt;&lt;p&gt;8位宽寄存器来配置中断优先级&lt;/p&gt;&#10;&lt;p&gt;ARM Cortex-M支持2^8=256个中断优先级&lt;/p&gt;&#10;&lt;p&gt;STM32只用高四位[7:4]，所以STM32提供2^4=16个中断优先级&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250804141722815" class="gallery-image" data-flex-basis="1116px" data-flex-grow="465" height="133" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250804141722815.png" width="619"&gt;&lt;/p&gt;&#10;&lt;p&gt;STM32中断分为抢占优先级和子优先级&lt;/p&gt;&#10;&lt;p&gt;抢占优先级： 抢占优先级高的中断可以打断正在执行但抢占优先级低的中断&lt;/p&gt;&#10;&lt;p&gt;子优先级：当同时发生具有相同抢占优先级的两个中断时，子优先级数值小的优先执行&lt;/p&gt;&#10;&lt;p&gt;（中断优先级数字越小越优先）&lt;/p&gt;&#10;&lt;h3 id="分配方式"&gt;&lt;a href="#%e5%88%86%e9%85%8d%e6%96%b9%e5%bc%8f" class="header-anchor"&gt;&lt;/a&gt;分配方式&#13;&#10;&lt;/h3&gt;&lt;p&gt;&lt;img alt="image-20250804141852953" class="gallery-image" data-flex-basis="598px" data-flex-grow="249" height="534" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250804141852953.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250804141852953_hu_86ca46c2a8d03dc.png 800w, https://zeseanblog.top/p/freertos/images/image-20250804141852953.png 1331w" width="1331"&gt;&lt;/p&gt;&#10;&lt;p&gt;如：HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4 ）设置优先级分组4&lt;/p&gt;&#10;&lt;h3 id="注意"&gt;&lt;a href="#%e6%b3%a8%e6%84%8f" class="header-anchor"&gt;&lt;/a&gt;注意&#13;&#10;&lt;/h3&gt;&lt;p&gt;1 、低于 configMAX_SYSCALL_INTERRUPT_PRIORITY 优先级的中断里才允许调FreeRTOS 的 API 函数&lt;/p&gt;&#10;&lt;p&gt;2 、建议将所有优先级位指定为抢占优先级位，方便 FreeRTOS 管理&lt;/p&gt;&#10;&lt;p&gt;HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4 ）&lt;/p&gt;&#10;&lt;p&gt;3 、中断优先级数值越小越优先，任务优先级数值越大越优先&lt;/p&gt;&#10;&lt;h1 id="七临界段代码保护-任务调度器挂起和恢复"&gt;&lt;a href="#%e4%b8%83%e4%b8%b4%e7%95%8c%e6%ae%b5%e4%bb%a3%e7%a0%81%e4%bf%9d%e6%8a%a4-%e4%bb%bb%e5%8a%a1%e8%b0%83%e5%ba%a6%e5%99%a8%e6%8c%82%e8%b5%b7%e5%92%8c%e6%81%a2%e5%a4%8d" class="header-anchor"&gt;&lt;/a&gt;七、临界段代码保护 任务调度器挂起和恢复&#13;&#10;&lt;/h1&gt;&lt;h2 id="1临界段代码保护"&gt;&lt;a href="#1%e4%b8%b4%e7%95%8c%e6%ae%b5%e4%bb%a3%e7%a0%81%e4%bf%9d%e6%8a%a4" class="header-anchor"&gt;&lt;/a&gt;1.临界段代码保护&#13;&#10;&lt;/h2&gt;&lt;p&gt;临界段：指那些必须完整运行，不能被（中断、任务调度PendSV）打断的代码段&lt;/p&gt;&#10;&lt;p&gt;需要保护：&lt;/p&gt;&#10;&lt;p&gt;1.严格时序初始化的外设&lt;/p&gt;&#10;&lt;p&gt;2.系统自身需求&lt;/p&gt;&#10;&lt;p&gt;3.用户需求&lt;/p&gt;&#10;&lt;h2 id="2临界段代码保护函数"&gt;&lt;a href="#2%e4%b8%b4%e7%95%8c%e6%ae%b5%e4%bb%a3%e7%a0%81%e4%bf%9d%e6%8a%a4%e5%87%bd%e6%95%b0" class="header-anchor"&gt;&lt;/a&gt;2.临界段代码保护函数&#13;&#10;&lt;/h2&gt;&lt;p&gt;&lt;img alt="image-20250804145449284" class="gallery-image" data-flex-basis="892px" data-flex-grow="371" height="163" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250804145449284.png" width="606"&gt;&lt;/p&gt;&#10;&lt;p&gt;临界区屏蔽中断，系统任务调度和ISR都靠中断，因此临界区不能长&lt;/p&gt;&#10;&lt;h3 id="3任务调度器挂起和恢复"&gt;&lt;a href="#3%e4%bb%bb%e5%8a%a1%e8%b0%83%e5%ba%a6%e5%99%a8%e6%8c%82%e8%b5%b7%e5%92%8c%e6%81%a2%e5%a4%8d" class="header-anchor"&gt;&lt;/a&gt;3.任务调度器挂起和恢复&#13;&#10;&lt;/h3&gt;&lt;p&gt;挂起任务调度器，就是不许任务切换，不需要关闭中断&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250804151438414" class="gallery-image" data-flex-basis="1387px" data-flex-grow="578" height="106" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250804151438414.png" width="613"&gt;&lt;/p&gt;&#10;&lt;p&gt;1.挂起任务调度器未关闭中断&lt;/p&gt;&#10;&lt;p&gt;2.防止任务间资源争夺，中断照样响应&lt;/p&gt;&#10;&lt;h1 id="八freertos列表和列表项"&gt;&lt;a href="#%e5%85%abfreertos%e5%88%97%e8%a1%a8%e5%92%8c%e5%88%97%e8%a1%a8%e9%a1%b9" class="header-anchor"&gt;&lt;/a&gt;八、FreeRTOS列表和列表项&#13;&#10;&lt;/h1&gt;&lt;h2 id="1列表和列表项"&gt;&lt;a href="#1%e5%88%97%e8%a1%a8%e5%92%8c%e5%88%97%e8%a1%a8%e9%a1%b9" class="header-anchor"&gt;&lt;/a&gt;1.列表和列表项&#13;&#10;&lt;/h2&gt;&lt;p&gt;列表是FreeRTOS的一个数据结构，类似链表，用于跟踪FreeRTOS的任务&lt;/p&gt;&#10;&lt;p&gt;列表项是在列表中的项目&lt;/p&gt;&#10;&lt;p&gt;FreeRTOS中列表是&lt;strong&gt;双向环形链表&lt;/strong&gt;&lt;/p&gt;&#10; &lt;img src="images/image-20250804155007010.png" alt="image-20250804155007010" style="zoom:67%;" /&gt;&#10;&lt;p&gt;非连续地址，人为连接到一起，数目后期添加，随时可以改变&lt;/p&gt;&#10;&lt;h3 id="列表相关结构体"&gt;&lt;a href="#%e5%88%97%e8%a1%a8%e7%9b%b8%e5%85%b3%e7%bb%93%e6%9e%84%e4%bd%93" class="header-anchor"&gt;&lt;/a&gt;列表相关结构体&#13;&#10;&lt;/h3&gt;&lt;p&gt;&lt;img alt="image-20250804155613541" class="gallery-image" data-flex-basis="729px" data-flex-grow="304" height="347" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250804155613541.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250804155613541_hu_e4faf885689f2471.png 800w, https://zeseanblog.top/p/freertos/images/image-20250804155613541.png 1055w" width="1055"&gt;&lt;/p&gt;&#10;&lt;p&gt;1.校验值：用于调试，默认不开启&lt;/p&gt;&#10;&lt;p&gt;2.uxNumberOfltems，记录列表项的个数&lt;/p&gt;&#10;&lt;p&gt;3.pxIndex：指向列表中的某个列表项，用于遍历列表项&lt;/p&gt;&#10;&lt;p&gt;4.xListEnd是迷你列表项，排在末尾&lt;/p&gt;&#10;&lt;img src="images/image-20250804160002038.png" alt="image-20250804160002038" style="zoom:50%;" /&gt;&#10;&lt;h3 id="列表项结构体"&gt;&lt;a href="#%e5%88%97%e8%a1%a8%e9%a1%b9%e7%bb%93%e6%9e%84%e4%bd%93" class="header-anchor"&gt;&lt;/a&gt;列表项结构体&#13;&#10;&lt;/h3&gt;&lt;p&gt;&lt;img alt="image-20250804160223478" class="gallery-image" data-flex-basis="800px" data-flex-grow="333" height="354" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250804160223478.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250804160223478_hu_2ac780c1efa8030e.png 800w, https://zeseanblog.top/p/freertos/images/image-20250804160223478.png 1180w" width="1180"&gt;&lt;/p&gt;&#10;&lt;p&gt;1.xItemValue为列表项的值，对列表项进行排序（升序）&lt;/p&gt;&#10;&lt;p&gt;2.pxNext 和 pxPrevious 分别用于指向列表中列表项的下一个列表项和上一个列表项&lt;/p&gt;&#10;&lt;p&gt;3.pxOwner指向包含列表项的对象（通常是任务控制块）&lt;/p&gt;&#10;&lt;p&gt;3.pxContainer指向列表项所在列表&lt;/p&gt;&#10;&lt;img src="images/image-20250804160559934.png" alt="image-20250804160559934" style="zoom:50%;" /&gt;&#10;&lt;h3 id="迷你列表项结构体"&gt;&lt;a href="#%e8%bf%b7%e4%bd%a0%e5%88%97%e8%a1%a8%e9%a1%b9%e7%bb%93%e6%9e%84%e4%bd%93" class="header-anchor"&gt;&lt;/a&gt;迷你列表项结构体&#13;&#10;&lt;/h3&gt;&lt;p&gt;用于标记列表的末尾和挂载其他插入列表中的列表项&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250804160919917" class="gallery-image" data-flex-basis="928px" data-flex-grow="387" height="285" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250804160919917.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250804160919917_hu_e3d1ae42f8419d36.png 800w, https://zeseanblog.top/p/freertos/images/image-20250804160919917.png 1103w" width="1103"&gt;&lt;/p&gt;&#10;&lt;p&gt;少了pxOwner和pxContainer&lt;/p&gt;&#10;&lt;h3 id="列表和列表项的关系"&gt;&lt;a href="#%e5%88%97%e8%a1%a8%e5%92%8c%e5%88%97%e8%a1%a8%e9%a1%b9%e7%9a%84%e5%85%b3%e7%b3%bb" class="header-anchor"&gt;&lt;/a&gt;列表和列表项的关系&#13;&#10;&lt;/h3&gt;&lt;p&gt;列表初始化就有末尾列表项，而无列表项&lt;/p&gt;&#10;&lt;img src="images/image-20250804161344141.png" alt="image-20250804161344141" style="zoom: 50%;" /&gt;&#10;&lt;p&gt;初始末尾列表项的xItemValue=0xFFFFFFFF&lt;/p&gt;&#10;&lt;p&gt;*pxPrevious，*pxNext都是指向的列表项的头指针（首地址）&lt;/p&gt;&#10;&lt;p&gt;pxIndex不遍历时不指向&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250804162946703" class="gallery-image" data-flex-basis="625px" data-flex-grow="260" height="465" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250804162946703.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250804162946703_hu_df53ed6185858f5d.png 800w, https://zeseanblog.top/p/freertos/images/image-20250804162946703.png 1212w" width="1212"&gt;&lt;/p&gt;&#10;&lt;h2 id="2列表及列表项api"&gt;&lt;a href="#2%e5%88%97%e8%a1%a8%e5%8f%8a%e5%88%97%e8%a1%a8%e9%a1%b9api" class="header-anchor"&gt;&lt;/a&gt;2.列表及列表项API&#13;&#10;&lt;/h2&gt;&lt;p&gt;&lt;img alt="image-20250804170048461" class="gallery-image" data-flex-basis="632px" data-flex-grow="263" height="379" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250804170048461.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250804170048461_hu_77542b2874a6634f.png 800w, https://zeseanblog.top/p/freertos/images/image-20250804170048461.png 999w" width="999"&gt;&lt;/p&gt;&#10;&lt;h1 id="九任务调度机制"&gt;&lt;a href="#%e4%b9%9d%e4%bb%bb%e5%8a%a1%e8%b0%83%e5%ba%a6%e6%9c%ba%e5%88%b6" class="header-anchor"&gt;&lt;/a&gt;九、任务调度机制*&#13;&#10;&lt;/h1&gt;&lt;h2 id="1开启任务调度器"&gt;&lt;a href="#1%e5%bc%80%e5%90%af%e4%bb%bb%e5%8a%a1%e8%b0%83%e5%ba%a6%e5%99%a8" class="header-anchor"&gt;&lt;/a&gt;1.开启任务调度器&#13;&#10;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;vTaskStartScheduler()中&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;启动任务调度器&lt;/p&gt;&#10;&lt;h3 id="1创建空闲任务"&gt;&lt;a href="#1%e5%88%9b%e5%bb%ba%e7%a9%ba%e9%97%b2%e4%bb%bb%e5%8a%a1" class="header-anchor"&gt;&lt;/a&gt;1.创建空闲任务&#13;&#10;&lt;/h3&gt;&lt;p&gt;先判断创建方式：静态创建、动态创建；根据宏configSUPPORT_STATIC_ALLOCATION选择&lt;/p&gt;&#10;&lt;h3 id="2定时器任务"&gt;&lt;a href="#2%e5%ae%9a%e6%97%b6%e5%99%a8%e4%bb%bb%e5%8a%a1" class="header-anchor"&gt;&lt;/a&gt;2.定时器任务&#13;&#10;&lt;/h3&gt;&lt;p&gt;如果使能软件定时器，创建定时器任务&lt;/p&gt;&#10;&lt;p&gt;根据宏configUSE_TIMERS；xTimerCreateTimerTask()&lt;/p&gt;&#10;&lt;p&gt;若创建成功&lt;/p&gt;&#10;&lt;h3 id="3关闭中断"&gt;&lt;a href="#3%e5%85%b3%e9%97%ad%e4%b8%ad%e6%96%ad" class="header-anchor"&gt;&lt;/a&gt;3.关闭中断&#13;&#10;&lt;/h3&gt;&lt;p&gt;防止调度器开启之前或过程中，受中断干扰，会在运行第一个任务时打开中断&lt;/p&gt;&#10;&lt;p&gt;portDISABLE_INTERRUPTS();&lt;/p&gt;&#10;&lt;h3 id="4初始化全局变量"&gt;&lt;a href="#4%e5%88%9d%e5%a7%8b%e5%8c%96%e5%85%a8%e5%b1%80%e5%8f%98%e9%87%8f" class="header-anchor"&gt;&lt;/a&gt;4.初始化全局变量&#13;&#10;&lt;/h3&gt;&lt;p&gt;并将任务调度器设置为已运行&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;//阻塞时间默认最大值&#10;xNextTaskUnblockTime = portMAX_DELAY;&#10;//调度器运行状态&#10;xSchedulerRunning = pdTRUE;&#10;//初始节拍 0&#10;xTickCount = ( TickType_t ) configINITIAL_TICK_COUNT;&#10;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="5调用xportstartscheduler"&gt;&lt;a href="#5%e8%b0%83%e7%94%a8xportstartscheduler" class="header-anchor"&gt;&lt;/a&gt;5.调用xPortStartScheduler();&#13;&#10;&lt;/h3&gt;&lt;p&gt;作用：该函数用于完成启动任务调度器中与硬件架构相关的配置部分，以及启动第一个任务&lt;/p&gt;&#10;&lt;h4 id="51检测配置是否有误"&gt;&lt;a href="#51%e6%a3%80%e6%b5%8b%e9%85%8d%e7%bd%ae%e6%98%af%e5%90%a6%e6%9c%89%e8%af%af" class="header-anchor"&gt;&lt;/a&gt;5.1检测配置是否有误&#13;&#10;&lt;/h4&gt;&lt;p&gt;用户在 FreeRTOSConfig.h 文件中对中断的相关配置&lt;/p&gt;&#10;&lt;h4 id="52配置-pendsv-和-systick"&gt;&lt;a href="#52%e9%85%8d%e7%bd%ae-pendsv-%e5%92%8c-systick" class="header-anchor"&gt;&lt;/a&gt;5.2配置 PendSV 和 SysTick&#13;&#10;&lt;/h4&gt;&lt;p&gt;配置 PendSV 和 SysTick 的中断优先级为最低优先级&lt;/p&gt;&#10;&lt;pre&gt;&lt;code&gt;portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;&#10;portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;h4 id="53调用vportsetuptimerinterrupt"&gt;&lt;a href="#53%e8%b0%83%e7%94%a8vportsetuptimerinterrupt" class="header-anchor"&gt;&lt;/a&gt;5.3调用vPortSetupTimerInterrupt()；&#13;&#10;&lt;/h4&gt;&lt;p&gt;函数中在配置SysTick&lt;/p&gt;&#10;&lt;p&gt;SysTick控制及状态寄存器（地址：0xE000_E010）&lt;/p&gt;&#10;&lt;p&gt;SysTick当前数值寄存器（地址：0xE000_E018）&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;span class="lnt"&gt;7&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/*&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;配置寄存器&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;#define portNVIC_SYSTICK_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000e010 ) )&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;#define portNVIC_SYSTICK_CURRENT_VALUE_REG ( *( ( volatile uint32_t * ) 0xe000e018 ) )&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;portNVIC_SYSTICK_CTRL_REG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0UL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;portNVIC_SYSTICK_CURRENT_VALUE_REG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0UL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;img src="images/image-20250804202454119.png" alt="image-20250804202454119" style="zoom:67%;" /&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/*&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;#define portNVIC_SYSTICK_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000e010 ) )&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;#define portNVIC_SYSTICK_LOAD_REG ( *( ( volatile uint32_t * ) 0xe000e014 ) )&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/*&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;F103C8中&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;uint32_t SystemCoreClock = 16000000;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;#define configCPU_CLOCK_HZ &#9;SystemCoreClock //定义CPU主频, 单位: Hz, 无默认需定义&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;#define configSYSTICK_CLOCK_HZ (configCPU_CLOCK_HZ / 8)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;#define configTICK_RATE_HZ 20&#9;&#9;&#9;&#9;&#9;/* 定义系统时钟节拍频率, 单位: Hz, 无默认需定义 */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;portNVIC_SYSTICK_LOAD_REG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;configSYSTICK_CLOCK_HZ&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;configTICK_RATE_HZ&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1UL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;portNVIC_SYSTICK_CTRL_REG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;portNVIC_SYSTICK_CLK_BIT_CONFIG&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;portNVIC_SYSTICK_INT_BIT&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;portNVIC_SYSTICK_ENABLE_BIT&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;5.4初始化临界区嵌套计数器为 0&lt;/p&gt;&#10;&lt;p&gt;uxCriticalNesting = 0;&lt;/p&gt;&#10;&lt;p&gt;5.5调用函数 prvEnableVFP() 使能 FPU&lt;/p&gt;&#10;&lt;p&gt;Cortex M3没有FPU&lt;/p&gt;&#10;&lt;p&gt;5.6调用函数 prvStartFirstTask() 启动第一个任务&lt;/p&gt;&#10;&lt;h2 id="2启动第一个任务"&gt;&lt;a href="#2%e5%90%af%e5%8a%a8%e7%ac%ac%e4%b8%80%e4%b8%aa%e4%bb%bb%e5%8a%a1" class="header-anchor"&gt;&lt;/a&gt;2.启动第一个任务&#13;&#10;&lt;/h2&gt;&lt;p&gt;要启动的第一个任务是任务 A，那么就需要将任务A的寄存器值恢复到CPU寄存器&lt;/p&gt;&#10;&lt;p&gt;任务 A 的寄存器值，在一开始创建任务时就保存在任务堆栈里&lt;/p&gt;&#10;&lt;p&gt;注意：&lt;/p&gt;&#10;&lt;p&gt;1、中断产生时，硬件自动将 xPSR，PC(R15) ，LR(R14) ，R12 ，R3-R0出/入栈；而 R4~R11需要手动出/入栈&lt;/p&gt;&#10;&lt;p&gt;2 、进入中断后硬件会强制使用 MSP 指针 ，此时 LR(R14 ）的值将会被自动被更新为特殊的 EXC_RETURN&lt;/p&gt;&#10;&lt;p&gt;prvStartFirstTask()&lt;/p&gt;&#10;&lt;p&gt;&amp;hellip;.&lt;/p&gt;&#10;&lt;p&gt;/* Call SVC to start the first task. */&#10;svc 0&lt;/p&gt;&#10;&lt;p&gt;触发SVC中断，启动第一个任务&lt;/p&gt;&#10;&lt;p&gt;#define vPortSVCHandler SVC_Handler&lt;/p&gt;&#10;&lt;h3 id="svc中断"&gt;&lt;a href="#svc%e4%b8%ad%e6%96%ad" class="header-anchor"&gt;&lt;/a&gt;SVC中断&#13;&#10;&lt;/h3&gt;&lt;p&gt;只在启动第一次任务时会调用一次，以后不调用&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250804212919268" class="gallery-image" data-flex-basis="212px" data-flex-grow="88" height="569" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250804212919268.png" width="503"&gt;&lt;/p&gt;&#10;&lt;h3 id="出栈压栈汇编指令详解"&gt;&lt;a href="#%e5%87%ba%e6%a0%88%e5%8e%8b%e6%a0%88%e6%b1%87%e7%bc%96%e6%8c%87%e4%bb%a4%e8%af%a6%e8%a7%a3" class="header-anchor"&gt;&lt;/a&gt;出栈/压栈汇编指令详解&#13;&#10;&lt;/h3&gt;&lt;p&gt;&lt;img alt="image-20250804214029244" class="gallery-image" data-flex-basis="596px" data-flex-grow="248" height="478" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250804214029244.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250804214029244_hu_81eb288841a9e55b.png 800w, https://zeseanblog.top/p/freertos/images/image-20250804214029244.png 1188w" width="1188"&gt;&lt;/p&gt;&#10;&lt;h2 id="3任务切换"&gt;&lt;a href="#3%e4%bb%bb%e5%8a%a1%e5%88%87%e6%8d%a2" class="header-anchor"&gt;&lt;/a&gt;3.任务切换&#13;&#10;&lt;/h2&gt;&lt;p&gt;任务切换本质：CPU寄存器的切换&lt;/p&gt;&#10;&lt;p&gt;就是把不同任务加载到CPU寄存器里&lt;/p&gt;&#10;&lt;p&gt;假设要把任务A切换到B：&lt;/p&gt;&#10;&lt;p&gt;第一步：暂停任务A，将此时任务A的寄存器保存（压栈）到任务堆栈，即保存现场&lt;/p&gt;&#10;&lt;p&gt;第二步：将任务B的寄存器值（存在任务堆栈中）恢复到CPU寄存器，即恢复现场&lt;/p&gt;&#10;&lt;p&gt;切换过程：保存A现场，恢复B现场，即上下文切换&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;需要手动的部分：R4-R11&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;切换：任务切换在PendSV中断服务函数里完成&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250804215919484" class="gallery-image" data-flex-basis="483px" data-flex-grow="201" height="554" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250804215919484.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250804215919484_hu_3b34f54a595d72e2.png 800w, https://zeseanblog.top/p/freertos/images/image-20250804215919484.png 1115w" width="1115"&gt;&lt;/p&gt;&#10;&lt;h3 id="如何触发pendsv中断"&gt;&lt;a href="#%e5%a6%82%e4%bd%95%e8%a7%a6%e5%8f%91pendsv%e4%b8%ad%e6%96%ad" class="header-anchor"&gt;&lt;/a&gt;如何触发PendSV中断&#13;&#10;&lt;/h3&gt;&lt;p&gt;1.滴答定时器中断调用&lt;/p&gt;&#10;&lt;p&gt;2.FreeRTOS相关API：portYIELD()；//底层函数&lt;/p&gt;&#10;&lt;p&gt;本质：向中断控制和状态寄存器ICSR的bit28写1挂起PendSV来启动PendSV中断&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;流程&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;1：滴答定时器中断处理函数SysTick_Handler()&lt;/p&gt;&#10;&lt;p&gt;启动了任务调度器，则进入xPortSysTickHandler()&lt;/p&gt;&#10;&lt;p&gt;判断xTaskIncrementTick()&lt;/p&gt;&#10;&lt;p&gt;则执行&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define portNVIC_INT_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000ed04 ) )&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define portNVIC_PENDSVSET_BIT ( 1UL &amp;lt;&amp;lt; 28UL )&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;//即向地址0xe000ed04 第28位写入1&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;portNVIC_INT_CTRL_REG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;portNVIC_PENDSVSET_BIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;img alt="image-20250805141250773" class="gallery-image" data-flex-basis="923px" data-flex-grow="384" height="239" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250805141250773.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250805141250773_hu_8090224c4c5f9963.png 800w, https://zeseanblog.top/p/freertos/images/image-20250805141250773.png 920w" width="920"&gt;&lt;/p&gt;&#10;&lt;p&gt;2:&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;#define portYIELD() &#10;{ &#10; portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; &#10; __dsb( portSY_FULL_READ_WRITE ); &#10; __isb( portSY_FULL_READ_WRITE ); &#10;}&#10;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="pendsv中断服务函数"&gt;&lt;a href="#pendsv%e4%b8%ad%e6%96%ad%e6%9c%8d%e5%8a%a1%e5%87%bd%e6%95%b0" class="header-anchor"&gt;&lt;/a&gt;PendSV中断服务函数&#13;&#10;&lt;/h3&gt;&lt;p&gt;FreeRTOSConfig.h中&lt;/p&gt;&#10;&lt;p&gt;#define xPortPendSVHandler PendSV_Handler&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;span class="lnt"&gt;15&#10;&lt;/span&gt;&lt;span class="lnt"&gt;16&#10;&lt;/span&gt;&lt;span class="lnt"&gt;17&#10;&lt;/span&gt;&lt;span class="lnt"&gt;18&#10;&lt;/span&gt;&lt;span class="lnt"&gt;19&#10;&lt;/span&gt;&lt;span class="lnt"&gt;20&#10;&lt;/span&gt;&lt;span class="lnt"&gt;21&#10;&lt;/span&gt;&lt;span class="lnt"&gt;22&#10;&lt;/span&gt;&lt;span class="lnt"&gt;23&#10;&lt;/span&gt;&lt;span class="lnt"&gt;24&#10;&lt;/span&gt;&lt;span class="lnt"&gt;25&#10;&lt;/span&gt;&lt;span class="lnt"&gt;26&#10;&lt;/span&gt;&lt;span class="lnt"&gt;27&#10;&lt;/span&gt;&lt;span class="lnt"&gt;28&#10;&lt;/span&gt;&lt;span class="lnt"&gt;29&#10;&lt;/span&gt;&lt;span class="lnt"&gt;30&#10;&lt;/span&gt;&lt;span class="lnt"&gt;31&#10;&lt;/span&gt;&lt;span class="lnt"&gt;32&#10;&lt;/span&gt;&lt;span class="lnt"&gt;33&#10;&lt;/span&gt;&lt;span class="lnt"&gt;34&#10;&lt;/span&gt;&lt;span class="lnt"&gt;35&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;__asm&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;xPortPendSVHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="n"&gt;uxCriticalNesting&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="n"&gt;pxCurrentTCB&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#9;&#9;&lt;span class="c1"&gt;//任务控制块地址&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="n"&gt;vTaskSwitchContext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//八字节对齐&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;PRESERVE8&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;mrs&lt;/span&gt; &lt;span class="n"&gt;r0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;psp&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;isb&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ldr&lt;/span&gt; &lt;span class="n"&gt;r3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pxCurrentTCB&lt;/span&gt; &#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ldr&lt;/span&gt; &lt;span class="n"&gt;r2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;r3&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;&#9;&#9;&#9;&#9;&lt;span class="c1"&gt;//r2存放任务控制块地址&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;stmdb&lt;/span&gt; &lt;span class="n"&gt;r0&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;r4&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;r11&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &#9;&lt;span class="c1"&gt;//r4到r11压入cpu任务栈&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;str&lt;/span&gt; &lt;span class="n"&gt;r0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;r2&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;stmdb&lt;/span&gt; &lt;span class="n"&gt;sp&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;r3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r14&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;mov&lt;/span&gt; &lt;span class="n"&gt;r0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;configMAX_SYSCALL_INTERRUPT_PRIORITY&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;msr&lt;/span&gt; &lt;span class="n"&gt;basepri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dsb&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;isb&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;bl&lt;/span&gt; &lt;span class="n"&gt;vTaskSwitchContext&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;mov&lt;/span&gt; &lt;span class="n"&gt;r0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;msr&lt;/span&gt; &lt;span class="n"&gt;basepri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ldmia&lt;/span&gt; &lt;span class="n"&gt;sp&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;r3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r14&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ldr&lt;/span&gt; &lt;span class="n"&gt;r1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;r3&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ldr&lt;/span&gt; &lt;span class="n"&gt;r0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;r1&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ldmia&lt;/span&gt; &lt;span class="n"&gt;r0&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;r4&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;r11&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;msr&lt;/span&gt; &lt;span class="n"&gt;psp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;isb&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;bx&lt;/span&gt; &lt;span class="n"&gt;r14&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;nop&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h1 id="十时间片调度"&gt;&lt;a href="#%e5%8d%81%e6%97%b6%e9%97%b4%e7%89%87%e8%b0%83%e5%ba%a6" class="header-anchor"&gt;&lt;/a&gt;十、时间片调度&#13;&#10;&lt;/h1&gt;&lt;p&gt;当多个任务的任务优先级相同时，CPU 会轮流的处理每一个任务，每个任务享有 CPU 处理的时间都是相同的，这个时间被称为时间片。&lt;/p&gt;&#10;&lt;p&gt;一个时间片就等于 SysTick 中断周期（可以由用户自行设置），CPU 给与了一个时间片运行一个任务，不管这个任务是否运行完成，CPU 都会跑到下一个任务。&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="img" class="gallery-image" data-flex-basis="471px" data-flex-grow="196" height="206" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/csdn-ec673027b9e7474581d3c3c5d3159ebd.png" width="405"&gt;&lt;/p&gt;&#10;&lt;p&gt;流程：&lt;/p&gt;&#10;&lt;p&gt;1.task1 运行完一个时间片切换到 task2&lt;/p&gt;&#10;&lt;p&gt;2.task2 运行完一个时间片切换至 task3&lt;/p&gt;&#10;&lt;p&gt;3.task3 运行阻塞(系统延时或等待信号量等)切换至下一个任务 task1&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;没有用完的时间片不会再使用&lt;/strong&gt;，下次任务 task3 得到执行还是按照一个时间片的时钟节拍运行&lt;/p&gt;&#10;&lt;p&gt;4.task1 运行完一个时间片之后，切换至 task2 运行&lt;/p&gt;&#10;&lt;h1 id="十一任务相关api"&gt;&lt;a href="#%e5%8d%81%e4%b8%80%e4%bb%bb%e5%8a%a1%e7%9b%b8%e5%85%b3api" class="header-anchor"&gt;&lt;/a&gt;十一、任务相关API&#13;&#10;&lt;/h1&gt;&lt;p&gt;&lt;img alt="image-20250805151211347" class="gallery-image" data-flex-basis="376px" data-flex-grow="156" height="693" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250805151211347.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250805151211347_hu_e2de76a4f0a3fb67.png 800w, https://zeseanblog.top/p/freertos/images/image-20250805151211347.png 1086w" width="1086"&gt;&lt;/p&gt;&#10;&lt;p&gt;不多介绍&lt;/p&gt;&#10;&lt;h1 id="十二时间管理"&gt;&lt;a href="#%e5%8d%81%e4%ba%8c%e6%97%b6%e9%97%b4%e7%ae%a1%e7%90%86" class="header-anchor"&gt;&lt;/a&gt;十二、时间管理&#13;&#10;&lt;/h1&gt;&lt;p&gt;&lt;img alt="image-20250805153017599" class="gallery-image" data-flex-basis="1517px" data-flex-grow="632" height="174" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250805153017599.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250805153017599_hu_159be6fd7bb21bb4.png 800w, https://zeseanblog.top/p/freertos/images/image-20250805153017599.png 1100w" width="1100"&gt;&lt;/p&gt;&#10;&lt;p&gt;· 相对延时：指每次延时都是从任务执行函数vTaskDelay()开始，延时指定的时间结束。&lt;/p&gt;&#10;&lt;p&gt;· 绝对延时：指每隔指定的时间，执行一次调用vTaskDelayUntil()函数的任务。&lt;/p&gt;&#10;&lt;p&gt;即:vTaskDelay()是从调用其本身开始计时，vTaskDelayUntil()是从调用任务开始计时&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;span class="lnt"&gt;15&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;BaseType_t&lt;/span&gt; &lt;span class="nf"&gt;xTaskDelayUntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;TickType_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pxPreviousWakeTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &#9;&#9;&#9;&#9;&#9;&#9; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;TickType_t&lt;/span&gt; &lt;span class="n"&gt;xTimeIncrement&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Perform an action every 10 ticks.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;vTaskFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;pvParameters&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;TickType_t&lt;/span&gt; &lt;span class="n"&gt;xLastWakeTime&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;TickType_t&lt;/span&gt; &lt;span class="n"&gt;xFrequency&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;xLastWakeTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;xTaskGetTickCount&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// Wait for the next cycle.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// Perform action here.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;vTaskDelayUntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;xLastWakeTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;xFrequency&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h1 id="十三freertos消息队列"&gt;&lt;a href="#%e5%8d%81%e4%b8%89freertos%e6%b6%88%e6%81%af%e9%98%9f%e5%88%97" class="header-anchor"&gt;&lt;/a&gt;十三、FreeRTOS消息队列&#13;&#10;&lt;/h1&gt;&lt;h2 id="1队列简介"&gt;&lt;a href="#1%e9%98%9f%e5%88%97%e7%ae%80%e4%bb%8b" class="header-anchor"&gt;&lt;/a&gt;1.队列简介&#13;&#10;&lt;/h2&gt;&lt;p&gt;任务到任务，任务到中断，中断到任务数据交流的一种机制&lt;/p&gt;&#10;&lt;p&gt;为什么不用全局变量？&lt;/p&gt;&#10;&lt;p&gt;假设有一个全局变量a=0，现在俩个认为在写变量a&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250805174038545" class="gallery-image" data-flex-basis="1273px" data-flex-grow="530" height="164" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250805174038545.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250805174038545_hu_d02ef7dbbc872c33.png 800w, https://zeseanblog.top/p/freertos/images/image-20250805174038545.png 870w" width="870"&gt;&lt;/p&gt;&#10;&lt;p&gt;任务1执行到第二步，任务2打断，执行a++，此时a才是1，回到任务1的第三步，a为1，但执行两次a++。&lt;/p&gt;&#10;&lt;p&gt;因此全局变量数据无保护，当多任务操作数据时，数据受损&lt;/p&gt;&#10;&lt;h3 id="使用队列"&gt;&lt;a href="#%e4%bd%bf%e7%94%a8%e9%98%9f%e5%88%97" class="header-anchor"&gt;&lt;/a&gt;使用队列&#13;&#10;&lt;/h3&gt;&lt;p&gt;&lt;img alt="image-20250805174331194" class="gallery-image" data-flex-basis="985px" data-flex-grow="410" height="227" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250805174331194.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250805174331194_hu_c27c2352446e24cd.png 800w, https://zeseanblog.top/p/freertos/images/image-20250805174331194.png 932w" width="932"&gt;&lt;/p&gt;&#10;&lt;p&gt;为什么会安全？因为封装了临界区，即关闭中断，读写队列都有保护，防止多任务冲突&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="img" class="gallery-image" data-flex-basis="985px" data-flex-grow="410" height="143" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/csdn-b69d543cfa214f07ac2e3f0009eec667.png" width="587"&gt;&lt;/p&gt;&#10;&lt;p&gt;队列存储数量有限、大小固定的数据。队列的每个数据叫队列项目&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250805174900810" class="gallery-image" data-flex-basis="728px" data-flex-grow="303" height="246" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250805174900810.png" width="747"&gt;&lt;/p&gt;&#10;&lt;h3 id="队列要点"&gt;&lt;a href="#%e9%98%9f%e5%88%97%e8%a6%81%e7%82%b9" class="header-anchor"&gt;&lt;/a&gt;队列要点&#13;&#10;&lt;/h3&gt;&lt;p&gt;1.数据入队出队：通常FIFO（先入先出），也可以LIFO（后入先出）&lt;/p&gt;&#10;&lt;p&gt;2.数据传递方式：freertos采用实际值，将数据拷贝至队列，在传递较大数据时可以传递指针&lt;/p&gt;&#10;&lt;p&gt;3.多任务访问：队列不属于某任务，任何任务、中断都可以读写&lt;/p&gt;&#10;&lt;p&gt;4.出入阻塞：当任务向队列读写时，可以指定阻塞时间，队列已满或空则无法入队、出队&lt;/p&gt;&#10;&lt;p&gt;阻塞时间是：0：直接返回不等待&lt;/p&gt;&#10;&lt;p&gt;​&#9;&#9;&#9;&#9;&#9;&#9;0~max：超时不入队则不等待&lt;/p&gt;&#10;&lt;p&gt;​&#9;&#9;&#9;&#9;&#9;&#9;max：死等&lt;/p&gt;&#10;&lt;h3 id="入出队阻塞"&gt;&lt;a href="#%e5%85%a5%e5%87%ba%e9%98%9f%e9%98%bb%e5%a1%9e" class="header-anchor"&gt;&lt;/a&gt;入/出队阻塞&#13;&#10;&lt;/h3&gt;&lt;p&gt;入队阻塞，队列满了，此时写不进去数据&lt;/p&gt;&#10;&lt;img src="images/image-20250805180519958.png" alt="image-20250805180519958" style="zoom:50%;" /&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;将该任务的状态列表项挂载再 pxDelayedTaskLisk；&lt;/li&gt;&#10;&lt;li&gt;将该任务的事件列表项挂载在 xTasksWaitingToSend；&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;出队阻塞，队列为空，此时读取不了数据：&lt;/p&gt;&#10;&lt;img src="images/image-20250805180611951.png" alt="image-20250805180611951" style="zoom:50%;" /&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;将该任务的状态列表项挂载再 pxDelayedTaskLisk；&lt;/li&gt;&#10;&lt;li&gt;将该任务的事件列表项挂载在 xTasksWaitingToReceive；&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;多任务都在等待同一个队列入队，都在阻塞，那当队列有空间，谁先进入就绪态:&lt;/p&gt;&#10;&lt;p&gt;那优先级最高的入队，若优先级相同，等最久的入队&lt;/p&gt;&#10;&lt;h2 id="2队列结构体"&gt;&lt;a href="#2%e9%98%9f%e5%88%97%e7%bb%93%e6%9e%84%e4%bd%93" class="header-anchor"&gt;&lt;/a&gt;2.队列结构体&#13;&#10;&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;span class="lnt"&gt;15&#10;&lt;/span&gt;&lt;span class="lnt"&gt;16&#10;&lt;/span&gt;&lt;span class="lnt"&gt;17&#10;&lt;/span&gt;&lt;span class="lnt"&gt;18&#10;&lt;/span&gt;&lt;span class="lnt"&gt;19&#10;&lt;/span&gt;&lt;span class="lnt"&gt;20&#10;&lt;/span&gt;&lt;span class="lnt"&gt;21&#10;&lt;/span&gt;&lt;span class="lnt"&gt;22&#10;&lt;/span&gt;&lt;span class="lnt"&gt;23&#10;&lt;/span&gt;&lt;span class="lnt"&gt;24&#10;&lt;/span&gt;&lt;span class="lnt"&gt;25&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;QueueDefinition&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int8_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;pcHead&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* 存储区域的起始地址 */&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int8_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;pcWriteTo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* 下一个写入的位置 */&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;union&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;QueuePointers_t&lt;/span&gt; &lt;span class="n"&gt;xQueue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &#9;&#9;&lt;span class="c1"&gt;//当用于队列时&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;SemaphoreData_t&lt;/span&gt; &lt;span class="n"&gt;xSemaphore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &#9;&lt;span class="c1"&gt;//当用于信号量时&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;List_t&lt;/span&gt; &lt;span class="n"&gt;xTasksWaitingToSend&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* 写入阻塞任务列表 */&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;List_t&lt;/span&gt; &lt;span class="n"&gt;xTasksWaitingToReceive&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* 读取阻塞任务列表 */&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;volatile&lt;/span&gt; &lt;span class="n"&gt;UBaseType_t&lt;/span&gt; &lt;span class="n"&gt;uxMessagesWaiting&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* 非空闲项目的数量 */&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;UBaseType_t&lt;/span&gt; &lt;span class="n"&gt;uxLength&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* 队列的长度 */&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;UBaseType_t&lt;/span&gt; &lt;span class="n"&gt;uxItemSize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* 队列项目的大小 */&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cm"&gt;/* 锁用于在任务因队列操作被阻塞前，防止中断或其他任务操作队列。 &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * 上锁期间，队列可以写入和读取消息，但不会操作队列阻塞任务列表， &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * 当有消息写入时，cTxLock加1，当有消息被读取时，cRxLock加1， &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * 在解锁时，会统一处理队列的阻塞任务列表 &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; */&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;volatile&lt;/span&gt; &lt;span class="kt"&gt;int8_t&lt;/span&gt; &lt;span class="n"&gt;cRxLock&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* 读取上锁计数器 */&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;volatile&lt;/span&gt; &lt;span class="kt"&gt;int8_t&lt;/span&gt; &lt;span class="n"&gt;cTxLock&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* 写入上锁计数器 */&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="c1"&gt;//以下省略一些条件编译&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;xQUEUE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h2 id="3队列相关api函数"&gt;&lt;a href="#3%e9%98%9f%e5%88%97%e7%9b%b8%e5%85%b3api%e5%87%bd%e6%95%b0" class="header-anchor"&gt;&lt;/a&gt;3.队列相关API函数&#13;&#10;&lt;/h2&gt;&lt;p&gt;主要流程:创建队列-&amp;gt;写队列-&amp;gt;读队列&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250805192810878" class="gallery-image" data-flex-basis="1413px" data-flex-grow="589" height="110" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250805192810878.png" width="648"&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define xQueueCreate( uxQueueLength, uxItemSize ) &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="nf"&gt;xQueueGenericCreate&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt; &lt;span class="n"&gt;uxQueueLength&lt;/span&gt; &lt;span class="p"&gt;),(&lt;/span&gt; &lt;span class="n"&gt;uxItemSize&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queueQUEUE_TYPE_BASE&lt;/span&gt; &lt;span class="p"&gt;))&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;其中queueQUEUE_TYPE_BASE代表不同创建类型的功能，实际都是基于一个函数实现的&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;#define queueQUEUE_TYPE_BASE ( ( uint8_t ) 0U ) &#9;&#9;&#9;&#9;/* 队列 */ &#10;#define queueQUEUE_TYPE_SET ( ( uint8_t ) 0U ) &#9;&#9;&#9;&#9;/* 队列集 */ &#10;#define queueQUEUE_TYPE_MUTEX ( ( uint8_t ) 1U ) &#9;&#9;&#9;/* 互斥信号量 */ &#10;#define queueQUEUE_TYPE_COUNTING_SEMAPHORE ( ( uint8_t ) 2U ) &#9;/* 计数型信号量 */ &#10;#define queueQUEUE_TYPE_BINARY_SEMAPHORE ( ( uint8_t ) 3U )&#9;&#9;/* 二值信号量 */ &#10;#define queueQUEUE_TYPE_RECURSIVE_MUTEX ( ( uint8_t ) 4U ) &#9;&#9;/* 递归互斥信号量 */&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;QueueHandle_t xQueueCreate( uxQueueLength, uxItemSize )&lt;/p&gt;&#10;&lt;p&gt;uxQueueLength:队列长度&lt;/p&gt;&#10;&lt;p&gt;uxItemSize：队列项大小&lt;/p&gt;&#10;&lt;p&gt;返回值QueueHandle_t句柄&lt;/p&gt;&#10;&lt;p&gt;NULL：创建失败，其他值：创建成功，返回句柄&lt;/p&gt;&#10;&lt;h3 id="31写入消息api"&gt;&lt;a href="#31%e5%86%99%e5%85%a5%e6%b6%88%e6%81%afapi" class="header-anchor"&gt;&lt;/a&gt;3.1写入消息API&#13;&#10;&lt;/h3&gt;&lt;p&gt;&lt;img alt="image-20250805193852464" class="gallery-image" data-flex-basis="1026px" data-flex-grow="427" height="174" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250805193852464.png" width="744"&gt;&lt;/p&gt;&#10;&lt;p&gt;这四个函数都是对xQueueGenericSend()的宏定义&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define xQueueSend(xQueue, pvItemToQueue, xTicksToWait) &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;xQueueGenericSend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;xQueue&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;pvItemToQueue&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;xTicksToWait&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;queueSEND_TO_BACK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define xQueueSendToBack( xQueue, pvItemToQueue, xTicksToWait) &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;xQueueGenericSend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;xQueue&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;pvItemToQueue&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;xTicksToWait&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;queueSEND_TO_BACK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define xQueueSendToFront( xQueue, pvItemToQueue, xTicksToWait) &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;xQueueGenericSend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;xQueue&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;pvItemToQueue&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;xTicksToWait&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;queueSEND_TO_FRONT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define xQueueOverwrite( xQueue, pvItemToQueue) &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;xQueueGenericSend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;xQueue&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;pvItemToQueue&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;queueOVERWRITE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;xQueueGenericSend为&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;BaseType_t xQueueGenericSend( QueueHandle_t &#9; xQueue, &#10; &#9;&#9;&#9;&#9;&#9; const void * const pvItemToQueue, &#10; &#9;&#9;&#9;&#9;&#9; TickType_t &#9; xTicksToWait, &#10; &#9;&#9;&#9;&#9;&#9; const BaseType_t xCopyPosition); &#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img alt="image-20250805194502113" class="gallery-image" data-flex-basis="477px" data-flex-grow="198" height="437" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250805194502113.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250805194502113_hu_474c7e7a5e2e6293.png 800w, https://zeseanblog.top/p/freertos/images/image-20250805194502113.png 869w" width="869"&gt;&lt;/p&gt;&#10;&lt;h3 id="32读取消息api"&gt;&lt;a href="#32%e8%af%bb%e5%8f%96%e6%b6%88%e6%81%afapi" class="header-anchor"&gt;&lt;/a&gt;3.2读取消息API&#13;&#10;&lt;/h3&gt;&lt;p&gt;&lt;img alt="image-20250805194543783" class="gallery-image" data-flex-basis="1707px" data-flex-grow="711" height="103" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250805194543783.png" width="733"&gt;&lt;/p&gt;&#10;&lt;p&gt;xQueueReceive&lt;/p&gt;&#10;&lt;p&gt;从队列中读取消息，并且消息读取成功后，会将消息从队列中移除&lt;/p&gt;&#10;&lt;img src="images/image-20250805194845838.png" alt="image-20250805194845838" style="zoom:67%;" /&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;BaseType_t xQueueReceive( QueueHandle_t xQueue,&#10; void * const pvBuffer,&#10; TickType_t xTicksToWait );&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;xQueuePeek&lt;/p&gt;&#10;&lt;p&gt;不会删除的函数，参数一致&lt;/p&gt;&#10;&lt;h2 id="4队列相关api函数解析"&gt;&lt;a href="#4%e9%98%9f%e5%88%97%e7%9b%b8%e5%85%b3api%e5%87%bd%e6%95%b0%e8%a7%a3%e6%9e%90" class="header-anchor"&gt;&lt;/a&gt;4.队列相关API函数解析&#13;&#10;&lt;/h2&gt;&lt;h3 id="41xqueuecreate"&gt;&lt;a href="#41xqueuecreate" class="header-anchor"&gt;&lt;/a&gt;4.1xQueueCreate&#13;&#10;&lt;/h3&gt;&lt;p&gt;#define xQueueCreate( uxQueueLength, uxItemSize )&lt;/p&gt;&#10;&lt;p&gt;​&#9;&#9;&#9; xQueueGenericCreate( ( uxQueueLength ), ( uxItemSize ), ( queueQUEUE_TYPE_BASE ) )&lt;/p&gt;&#10;&lt;p&gt;对队列而言xQueueGenericCreate前两个入口参数有效&lt;/p&gt;&#10;&lt;p&gt;首先长度判断&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;if( ( uxQueueLength &amp;gt; ( UBaseType_t ) 0 ) &amp;amp;&amp;amp;&#10; ( ( SIZE_MAX / uxQueueLength ) &amp;gt;= uxItemSize ) &amp;amp;&amp;amp;&#10; ( ( SIZE_MAX - sizeof( Queue_t ) ) &amp;gt;= ( uxQueueLength * uxItemSize ) ) )&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;队列项存储区大小&lt;/p&gt;&#10;&lt;p&gt;xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize );&lt;/p&gt;&#10;&lt;p&gt;申请内存是队列项存储区+结构体存储区，并把首地址给到pxNewQueue&lt;/p&gt;&#10;&lt;p&gt;pxNewQueue = ( Queue_t * ) pvPortMalloc( sizeof( Queue_t ) + xQueueSizeInBytes );&lt;/p&gt;&#10;&lt;p&gt;再将地址指向队列项存储区&lt;/p&gt;&#10;&lt;p&gt;pucQueueStorage = ( uint8_t * ) pxNewQueue;&#10;pucQueueStorage += sizeof( Queue_t );&lt;/p&gt;&#10;&lt;img src="images/image-20250805203138966.png" alt="image-20250805203138966" style="zoom:50%;" /&gt;&#10;&lt;p&gt;执行&lt;/p&gt;&#10;&lt;p&gt;QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength,&#10;const UBaseType_t uxItemSize,&#10;const uint8_t ucQueueType )&lt;/p&gt;&#10;&lt;p&gt;除一个是存储区首地址，一个是队列结构体首地址pucQueueStorage，pxNewQueue外，由外部传入&lt;/p&gt;&#10;&lt;p&gt;prvInitialiseNewQueue( uxQueueLength, uxItemSize, &lt;strong&gt;pucQueueStorage&lt;/strong&gt;, ucQueueType, &lt;strong&gt;pxNewQueue&lt;/strong&gt; );&lt;/p&gt;&#10;&lt;p&gt;进入prvInitialiseNewQueue后&lt;/p&gt;&#10;&lt;p&gt;if( uxItemSize == ( UBaseType_t ) 0 )是信号量&lt;/p&gt;&#10;&lt;p&gt;否则是队列，执行以下行，将队列项存储区首地址给到队列首地址&lt;/p&gt;&#10;&lt;p&gt;pxNewQueue-&amp;gt;pcHead = ( int8_t * ) pucQueueStorage;&lt;/p&gt;&#10;&lt;p&gt;再进入&lt;/p&gt;&#10;&lt;p&gt;( void ) xQueueGenericReset( pxNewQueue, pdTRUE );&lt;/p&gt;&#10;&lt;h3 id="42xqueuesend"&gt;&lt;a href="#42xqueuesend" class="header-anchor"&gt;&lt;/a&gt;4.2xQueueSend&#13;&#10;&lt;/h3&gt;&lt;p&gt;#define xQueueSend( xQueue, pvItemToQueue, xTicksToWait )&lt;/p&gt;&#10;&lt;pre&gt;&lt;code&gt;&#9; xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), &#9;&#9;queueSEND_TO_BACK )&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;进入&lt;/p&gt;&#10;&lt;p&gt;xYieldRequired = prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );&lt;/p&gt;&#10;&lt;p&gt;如果尾部插入&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250805210830882" class="gallery-image" data-flex-basis="929px" data-flex-grow="387" height="228" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250805210830882.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250805210830882_hu_8a7b476ed1e95d0c.png 800w, https://zeseanblog.top/p/freertos/images/image-20250805210830882.png 883w" width="883"&gt;&lt;/p&gt;&#10;&lt;h1 id="十四信号量"&gt;&lt;a href="#%e5%8d%81%e5%9b%9b%e4%bf%a1%e5%8f%b7%e9%87%8f" class="header-anchor"&gt;&lt;/a&gt;十四、信号量&#13;&#10;&lt;/h1&gt;&lt;h2 id="1简介"&gt;&lt;a href="#1%e7%ae%80%e4%bb%8b" class="header-anchor"&gt;&lt;/a&gt;1.简介&#13;&#10;&lt;/h2&gt;&lt;p&gt;队列是发送数据，信号是发送状态，信号量是队列的衍生&lt;/p&gt;&#10;&lt;p&gt;信号量结局同步机制（我做完一件事告诉你），任务间的通信以及事件通知，对共享资源的有序访问&lt;/p&gt;&#10;&lt;p&gt;举例：&lt;/p&gt;&#10;&lt;p&gt;1.停车场车位是否还有（判断信号量是否还有资源）&lt;/p&gt;&#10;&lt;p&gt;2.停车场有空位（有资源），就可以将车开入（获取信号量）&lt;/p&gt;&#10;&lt;p&gt;3.停车场无空位（无资源），不可以将车开入（获取信号量失败），可以等待其他人开出（释放）&lt;/p&gt;&#10;&lt;img src="images/image-20250805214538146.png" alt="image-20250805214538146" style="zoom:50%;" /&gt;&#10;&lt;p&gt;如果最大值被限定为 1 ，那么它就是二值信号量；&#10;如果最大值不是 1 ，它就是计数型信号量。&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250805215045090" class="gallery-image" data-flex-basis="694px" data-flex-grow="289" height="371" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250805215045090.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250805215045090_hu_47a5d36768308485.png 800w, https://zeseanblog.top/p/freertos/images/image-20250805215045090.png 1073w" width="1073"&gt;&lt;/p&gt;&#10;&lt;h2 id="1二值信号量"&gt;&lt;a href="#1%e4%ba%8c%e5%80%bc%e4%bf%a1%e5%8f%b7%e9%87%8f" class="header-anchor"&gt;&lt;/a&gt;1.二值信号量&#13;&#10;&lt;/h2&gt;&lt;p&gt;本质：长度为1的队列，该队列只有空和满&lt;/p&gt;&#10;&lt;p&gt;通常用于互斥访问（一个任务持有锁，其他任务无法执行）和任务同步（一个任务等另一个任务完成才能执行下去），互斥信号量相似，但二值信号量可能导致优先级反转&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250805215532525" class="gallery-image" data-flex-basis="1065px" data-flex-grow="444" height="272" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250805215532525.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250805215532525_hu_20a7c39521efa82d.png 800w, https://zeseanblog.top/p/freertos/images/image-20250805215532525.png 1208w" width="1208"&gt;&lt;/p&gt;&#10;&lt;h3 id="二值信号量相关api函数"&gt;&lt;a href="#%e4%ba%8c%e5%80%bc%e4%bf%a1%e5%8f%b7%e9%87%8f%e7%9b%b8%e5%85%b3api%e5%87%bd%e6%95%b0" class="header-anchor"&gt;&lt;/a&gt;二值信号量相关API函数&#13;&#10;&lt;/h3&gt;&lt;p&gt;过程：创建-释放-获取&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250805215908052" class="gallery-image" data-flex-basis="645px" data-flex-grow="268" height="340" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250805215908052.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250805215908052_hu_2a407f0e1f474964.png 800w, https://zeseanblog.top/p/freertos/images/image-20250805215908052.png 914w" width="914"&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;创建&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;SemaphoreHandle_t xSemaphoreCreateBinary( void )&lt;/p&gt;&#10;&lt;img src="images/image-20250805220323164.png" alt="image-20250805220323164" style="zoom:50%;" /&gt;&#10;&lt;p&gt;&lt;strong&gt;释放&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;传入句柄xSemaphore&lt;/p&gt;&#10;&lt;p&gt;BaseType_t xSemaphoreGive( xSemaphore )&lt;/p&gt;&#10;&lt;p&gt;返回值pdPASS：成功&lt;/p&gt;&#10;&lt;p&gt;errQUEUE_FULL：失败&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;获取&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;传入句柄xSemaphore，阻塞时间xBlockTime ，死等为portMAX_DELAY&lt;/p&gt;&#10;&lt;p&gt;BaseType_t xSemaphoreTake( xSemaphore,xBlockTime )&lt;/p&gt;&#10;&lt;p&gt;返回值：pdTRUE 获取信号量成功&#10;pdFALSE 超时，获取信号量失败&lt;/p&gt;&#10;&lt;h2 id="2计数型信号量"&gt;&lt;a href="#2%e8%ae%a1%e6%95%b0%e5%9e%8b%e4%bf%a1%e5%8f%b7%e9%87%8f" class="header-anchor"&gt;&lt;/a&gt;2.计数型信号量&#13;&#10;&lt;/h2&gt;&lt;p&gt;计数型信号量相当于队列长度大于 1 的队列，因此计数型信号量能够容纳多个资源，这在计数型信号量被创建的时候确定的&lt;/p&gt;&#10;&lt;p&gt;适用场合：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;事件计数：每次事件发生，事件处理函数中释放计数型信号量，计数值+1，其他任务获取计数型信号量，计数值-1，初始计数值一般设为0&lt;/li&gt;&#10;&lt;li&gt;资源管理：信号量表示有效资源数量，任务必须先获取信号量，计数值-1，才能获取资源控制权，当计数值减到0时表示没有资源，当任务使用完资源后，必须释放，计数值+1,。信号量创建时一般等于最大资源数&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="计数型信号量相关api"&gt;&lt;a href="#%e8%ae%a1%e6%95%b0%e5%9e%8b%e4%bf%a1%e5%8f%b7%e9%87%8f%e7%9b%b8%e5%85%b3api" class="header-anchor"&gt;&lt;/a&gt;计数型信号量相关API&#13;&#10;&lt;/h3&gt;&lt;p&gt;创建-释放-获取&lt;/p&gt;&#10;&lt;p&gt;创建：&lt;/p&gt;&#10;&lt;img src="images/image-20250806145915838.png" alt="image-20250806145915838" style="zoom: 67%;" /&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;//uxMaxCount计数值的最大值限定&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;//uxInitialCount计数值的初始值&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define xSemaphoreCreateCounting(uxMaxCount, uxInitialCount)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &#9;&#9;&lt;span class="nf"&gt;xQueueCreateCountingSemaphore&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;uxMaxCount&lt;/span&gt;&lt;span class="p"&gt;),(&lt;/span&gt;&lt;span class="n"&gt;uxInitialCount&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;//返回值NULL创建失败&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;//其他值返回句柄 &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;获取和释放与二值相同&lt;/p&gt;&#10;&lt;h2 id="3优先级翻转"&gt;&lt;a href="#3%e4%bc%98%e5%85%88%e7%ba%a7%e7%bf%bb%e8%bd%ac" class="header-anchor"&gt;&lt;/a&gt;3.优先级翻转&#13;&#10;&lt;/h2&gt;&lt;p&gt;优先级翻转：高优先级任务反而慢执行，低优先级任务反而先执行&lt;/p&gt;&#10;&lt;p&gt;优先级翻转在抢占式内核中是很常见的问题，但是在实时操作系统中是不允许出现优先级翻转的，因为优先级翻转会破环任务的预期顺序，可能会导致未知的严重后果。在使用二值信号量的时候，经常会遇到优先级翻转问题。&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;角色&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;行为&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;优先级&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;H（高）&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;想用共享资源（如 UART、SPI）&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;3（最高）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;L（低）&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;已经拿到资源，正在用&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1（最低）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;M（中）&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;纯计算任务，不碰资源&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;&lt;img alt="image-20250806154108779" class="gallery-image" data-flex-basis="739px" data-flex-grow="308" height="449" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250806154108779.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250806154108779_hu_1013becb2ccac855.png 800w, https://zeseanblog.top/p/freertos/images/image-20250806154108779.png 1383w" width="1383"&gt;&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;L 先运行，&lt;strong&gt;拿到互斥量&lt;/strong&gt; → 进入临界区。&lt;/li&gt;&#10;&lt;li&gt;H 就绪，优先级最高，&lt;strong&gt;抢占 L&lt;/strong&gt;，但发现互斥量被占 → &lt;strong&gt;阻塞&lt;/strong&gt;。&lt;/li&gt;&#10;&lt;li&gt;M 就绪，优先级介于 H 和 L 之间 → &lt;strong&gt;抢占 L&lt;/strong&gt;，开始跑长计算。&lt;/li&gt;&#10;&lt;li&gt;结果：&#10;• &lt;strong&gt;H 必须等 M 跑完 → M 跑完 L 才能继续 → L 释放后 H 才能拿到&lt;/strong&gt;。&#10;• H 实际被 &lt;strong&gt;优先级远低于它的 L 间接阻塞&lt;/strong&gt;。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h2 id="4互斥信号量"&gt;&lt;a href="#4%e4%ba%92%e6%96%a5%e4%bf%a1%e5%8f%b7%e9%87%8f" class="header-anchor"&gt;&lt;/a&gt;4.互斥信号量&#13;&#10;&lt;/h2&gt;&lt;p&gt;互斥信号量是一个拥有优先级继承的二值信号量，在同步的应用中二值信号量最适合，互斥信号量适用与需要互斥访问的应用中。&lt;/p&gt;&#10;&lt;p&gt;优先级继承：当一个互斥信号量正在被一个低优先级的任务持有时， 如果此时有个高优先级的任务也尝试获取这个互斥信号量，那么这个高优先级的任务就会被阻塞。不过这个高优先级的任务会将低优先级任务的优先级提升到与自己相同的优先级。&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250806155928222" class="gallery-image" data-flex-basis="751px" data-flex-grow="313" height="442" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250806155928222.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250806155928222_hu_a173b6b95d8daa22.png 800w, https://zeseanblog.top/p/freertos/images/image-20250806155928222.png 1384w" width="1384"&gt;&lt;/p&gt;&#10;&lt;p&gt;依旧L阻塞H，但M就不会浪费时间执行，将优先级翻转危害降低。&lt;/p&gt;&#10;&lt;p&gt;就是不能完全消除影响，但尽可能把影响降到最低。&lt;/p&gt;&#10;&lt;p&gt;注意：互斥信号量不能用于中断服务函数中。原因：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;互斥信号量有任务优先级继承的机制，但中断不是任务，没有任务优先级，所以互斥信号量只能用于任务中，不能用于中断服务函数&lt;/li&gt;&#10;&lt;li&gt;中断服务函数中不能因为要等待互斥信号量而设置阻塞时间进入阻塞态&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="互斥信号量相关api"&gt;&lt;a href="#%e4%ba%92%e6%96%a5%e4%bf%a1%e5%8f%b7%e9%87%8f%e7%9b%b8%e5%85%b3api" class="header-anchor"&gt;&lt;/a&gt;互斥信号量相关API&#13;&#10;&lt;/h3&gt;&lt;p&gt;宏 configUSE_MUTEXES 置一&lt;/p&gt;&#10;&lt;p&gt;创建互斥信号量 -（ task ）获取信号量 -（ give ）释放信号量&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250806160514786" class="gallery-image" data-flex-basis="1492px" data-flex-grow="621" height="147" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250806160514786.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250806160514786_hu_7a03770570c57bc9.png 800w, https://zeseanblog.top/p/freertos/images/image-20250806160514786.png 914w" width="914"&gt;&lt;/p&gt;&#10;&lt;p&gt;无传入参数&lt;/p&gt;&#10;&lt;p&gt;xSemaphoreCreateMutex()&lt;/p&gt;&#10;&lt;p&gt;返回NULL创建失败，其他值返回句柄&lt;/p&gt;&#10;&lt;p&gt;获取与释放与二值信号量相同，只是不支持中断调用&lt;/p&gt;&#10;&lt;h1 id="十五队列集"&gt;&lt;a href="#%e5%8d%81%e4%ba%94%e9%98%9f%e5%88%97%e9%9b%86" class="header-anchor"&gt;&lt;/a&gt;十五、队列集&#13;&#10;&lt;/h1&gt;&lt;h2 id="1简介-1"&gt;&lt;a href="#1%e7%ae%80%e4%bb%8b-1" class="header-anchor"&gt;&lt;/a&gt;1.简介&#13;&#10;&lt;/h2&gt;&lt;p&gt;一个队列只允许任务间传递同一种数据类型，如果要传递不同数据类型，可以使用队列集。&lt;/p&gt;&#10;&lt;p&gt;作用：&lt;/p&gt;&#10;&lt;p&gt;对多个队列或信号量进行监听，不管哪个消息到来，都可以让任务退出阻塞状态&lt;/p&gt;&#10;&lt;p&gt;原始思路：&lt;/p&gt;&#10; &lt;img src="images/image-20250806164333227.png" alt="image-20250806164333227" style="zoom:50%;" /&gt;&#10;&lt;p&gt;队列集思路：&lt;/p&gt;&#10; &lt;img src="images/image-20250806164353656.png" alt="image-20250806164353656" style="zoom:50%;" /&gt;&#10;&lt;h2 id="2队列集相关api"&gt;&lt;a href="#2%e9%98%9f%e5%88%97%e9%9b%86%e7%9b%b8%e5%85%b3api" class="header-anchor"&gt;&lt;/a&gt;2.队列集相关API&#13;&#10;&lt;/h2&gt;&lt;p&gt;&lt;img alt="image-20250806164541592" class="gallery-image" data-flex-basis="724px" data-flex-grow="301" height="221" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250806164541592.png" width="667"&gt;&lt;/p&gt;&#10;&lt;h3 id="21创建xqueuecreateset"&gt;&lt;a href="#21%e5%88%9b%e5%bb%baxqueuecreateset" class="header-anchor"&gt;&lt;/a&gt;2.1创建xQueueCreateSet&#13;&#10;&lt;/h3&gt;&lt;p&gt;QueueSetHandle_t xQueueCreateSet( const UBaseType_t uxEventQueueLength );&lt;/p&gt;&#10;&lt;p&gt;参数：uxEventQueueLength 队列集可容纳的队列数量&lt;/p&gt;&#10;&lt;p&gt;返回值：NULL：队列集创建失败 其他值：创建成功，返回句柄&lt;/p&gt;&#10;&lt;h3 id="22添加xqueueaddtoset"&gt;&lt;a href="#22%e6%b7%bb%e5%8a%a0xqueueaddtoset" class="header-anchor"&gt;&lt;/a&gt;2.2添加xQueueAddToSet&#13;&#10;&lt;/h3&gt;&lt;p&gt;往队列集添加队列时，队列不能有消息&lt;/p&gt;&#10;&lt;p&gt;BaseType_t xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSemaphore ,&#10;QueueSetHandle_t xQueueSet );&lt;/p&gt;&#10;&lt;img src="images/image-20250806164917603.png" alt="image-20250806164917603" style="zoom:67%;" /&gt;&#10;&lt;h3 id="23移除"&gt;&lt;a href="#23%e7%a7%bb%e9%99%a4" class="header-anchor"&gt;&lt;/a&gt;2.3移除&#13;&#10;&lt;/h3&gt;&lt;p&gt;移除前不能有有效消息&lt;/p&gt;&#10;&lt;p&gt;BaseType_t xQueueRemoveFromSet( QueueSetMemberHandle_t xQueueOrSemaphore ,&#10;QueueSetHandle_t xQueueSet );&lt;/p&gt;&#10;&lt;img src="images/image-20250806165023992.png" alt="image-20250806165023992" style="zoom:67%;" /&gt;&#10;&lt;h3 id="24获取有效消息xqueueselectfromset"&gt;&lt;a href="#24%e8%8e%b7%e5%8f%96%e6%9c%89%e6%95%88%e6%b6%88%e6%81%afxqueueselectfromset" class="header-anchor"&gt;&lt;/a&gt;2.4获取有效消息xQueueSelectFromSet&#13;&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;QueueSetMemberHandle_t&lt;/span&gt; &lt;span class="nf"&gt;xQueueSelectFromSet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;QueueSetHandle_t&lt;/span&gt; &lt;span class="n"&gt;xQueueSet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&lt;span class="n"&gt;TickType_t&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;xTicksToWait&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;img src="images/image-20250806165250506.png" alt="image-20250806165250506" style="zoom:67%;" /&gt;&#10;&lt;h4 id="示例"&gt;&lt;a href="#%e7%a4%ba%e4%be%8b" class="header-anchor"&gt;&lt;/a&gt;示例&#13;&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;span class="lnt"&gt;15&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;member_handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;xQueueSelectFromSet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queueset_handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;portMAX_DELAY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;member_handle&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;queue_handle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;xQueueReceive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue_handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;portMAX_DELAY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="n"&gt;pdPASS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;队列queue_handle读取数据成功&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;member_handle&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;semphr_handle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;xSemaphoreTake&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;semphr_handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;portMAX_DELAY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="n"&gt;pdPASS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;获取信号量成功&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h1 id="十六事件标志组"&gt;&lt;a href="#%e5%8d%81%e5%85%ad%e4%ba%8b%e4%bb%b6%e6%a0%87%e5%bf%97%e7%bb%84" class="header-anchor"&gt;&lt;/a&gt;十六、事件标志组&#13;&#10;&lt;/h1&gt;&lt;h2 id="1简介-2"&gt;&lt;a href="#1%e7%ae%80%e4%bb%8b-2" class="header-anchor"&gt;&lt;/a&gt;1.简介&#13;&#10;&lt;/h2&gt;&lt;p&gt;事件标志组：用一个位表示时间是否发生&lt;/p&gt;&#10;&lt;p&gt;是一组事件标志位的集合，类似多个标志位&lt;/p&gt;&#10;&lt;p&gt;特点：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;每一个位表示一个事件（高八位不算）&lt;/li&gt;&#10;&lt;li&gt;每位事件的含义由用户决定如bit0表示按键，bit1表示消息是否接受&lt;/li&gt;&#10;&lt;li&gt;1：事件发生，0：事件未发生&lt;/li&gt;&#10;&lt;li&gt;任意任务和中断可读写这些位&lt;/li&gt;&#10;&lt;li&gt;可等待某一位，也可等待多位&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;一个事件组包含，EventBits_t是数据类型变量&lt;/p&gt;&#10;&lt;img src="images/image-20250806175133210.png" alt="image-20250806175133210" style="zoom:67%;" /&gt;&#10;&lt;p&gt;一个事件组最多可以存储 24 个事件标志&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250806175201301" class="gallery-image" data-flex-basis="1227px" data-flex-grow="511" height="251" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250806175201301.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250806175201301_hu_41a042c08b78db83.png 800w, https://zeseanblog.top/p/freertos/images/image-20250806175201301.png 1284w" width="1284"&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;与队列信号量区别&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="image-20250806175250430" class="gallery-image" data-flex-basis="1180px" data-flex-grow="492" height="353" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250806175250430.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250806175250430_hu_a08245ad99b0c6a0.png 800w, https://zeseanblog.top/p/freertos/images/image-20250806175250430_hu_cc667ebbe191020.png 1600w, https://zeseanblog.top/p/freertos/images/image-20250806175250430.png 1737w" width="1737"&gt;&lt;/p&gt;&#10;&lt;h2 id="2事件标志组相关api"&gt;&lt;a href="#2%e4%ba%8b%e4%bb%b6%e6%a0%87%e5%bf%97%e7%bb%84%e7%9b%b8%e5%85%b3api" class="header-anchor"&gt;&lt;/a&gt;2.事件标志组相关API&#13;&#10;&lt;/h2&gt;&lt;img src="images/image-20250806175445375.png" alt="image-20250806175445375" style="zoom: 50%;" /&gt;&#10;&lt;h3 id="21创建xeventgroupcreate"&gt;&lt;a href="#21%e5%88%9b%e5%bb%baxeventgroupcreate" class="header-anchor"&gt;&lt;/a&gt;2.1创建xEventGroupCreate&#13;&#10;&lt;/h3&gt;&lt;p&gt;EventGroupHandle_t xEventGroupCreate ( void) ;&lt;/p&gt;&#10;&lt;p&gt;返回NULL：失败&lt;/p&gt;&#10;&lt;p&gt;​&#9;&#9;其他值：成功返回句柄&lt;/p&gt;&#10;&lt;h3 id="22清零标志位xeventgroupclearbits"&gt;&lt;a href="#22%e6%b8%85%e9%9b%b6%e6%a0%87%e5%bf%97%e4%bd%8dxeventgroupclearbits" class="header-anchor"&gt;&lt;/a&gt;2.2清零标志位xEventGroupClearBits&#13;&#10;&lt;/h3&gt;&lt;p&gt;EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup,&#10;const EventBits_t uxBitsToClear )&lt;/p&gt;&#10;&lt;p&gt;参数：&lt;/p&gt;&#10;&lt;p&gt;xEventGroup 待操作的事件标志组句柄&#10;uxBitsToSet 待清零的事件标志位&lt;/p&gt;&#10;&lt;p&gt;返回：整数=清零事件标志位之前事件组中事件标志位的值&lt;/p&gt;&#10;&lt;h3 id="23设置标志位xeventgroupsetbits"&gt;&lt;a href="#23%e8%ae%be%e7%bd%ae%e6%a0%87%e5%bf%97%e4%bd%8dxeventgroupsetbits" class="header-anchor"&gt;&lt;/a&gt;2.3设置标志位xEventGroupSetBits&#13;&#10;&lt;/h3&gt;&lt;p&gt;EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,&#10;const EventBits_t uxBitsToSet )&lt;/p&gt;&#10;&lt;p&gt;参数：&lt;/p&gt;&#10;&lt;p&gt;xEventGroup 待操作的事件标志组句柄&#10;uxBitsToSet 待设置的事件标志位&lt;/p&gt;&#10;&lt;p&gt;返回：整数=函数返回时，事件组中的事件标志位值&lt;/p&gt;&#10;&lt;h3 id="24等待标志位xeventgroupwaitbits"&gt;&lt;a href="#24%e7%ad%89%e5%be%85%e6%a0%87%e5%bf%97%e4%bd%8dxeventgroupwaitbits" class="header-anchor"&gt;&lt;/a&gt;2.4等待标志位xEventGroupWaitBits&#13;&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;EventBits_t&lt;/span&gt; &lt;span class="nf"&gt;xEventGroupWaitBits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;EventGroupHandle_t&lt;/span&gt; &lt;span class="n"&gt;xEventGroup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;EventBits_t&lt;/span&gt; &#9;&lt;span class="n"&gt;uxBitsToWaitFor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;BaseType_t&lt;/span&gt; &#9;&lt;span class="n"&gt;xClearOnExit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;BaseType_t&lt;/span&gt; &#9;&lt;span class="n"&gt;xWaitForAllBits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9; &lt;span class="n"&gt;TickType_t&lt;/span&gt; &#9;&#9;&lt;span class="n"&gt;xTicksToWait&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;img src="images/image-20250806180148945.png" alt="image-20250806180148945" style="zoom: 67%;" /&gt;&#10;&lt;h3 id="25同步函数"&gt;&lt;a href="#25%e5%90%8c%e6%ad%a5%e5%87%bd%e6%95%b0" class="header-anchor"&gt;&lt;/a&gt;2.5同步函数&#13;&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-C" data-lang="C"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;EventBits_t&lt;/span&gt; &lt;span class="nf"&gt;xEventGroupSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EventGroupHandle_t&lt;/span&gt; &lt;span class="n"&gt;xEventGroup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;EventBits_t&lt;/span&gt; &lt;span class="n"&gt;uxBitsToSet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;EventBits_t&lt;/span&gt; &lt;span class="n"&gt;uxBitsToWaitFor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&lt;span class="n"&gt;TickType_t&lt;/span&gt; &#9; &lt;span class="n"&gt;xTicksToWait&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;img src="images/image-20250806191201673.png" alt="image-20250806191201673" style="zoom:67%;" /&gt;&#10;&lt;h3 id="示例-1"&gt;&lt;a href="#%e7%a4%ba%e4%be%8b-1" class="header-anchor"&gt;&lt;/a&gt;示例&#13;&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;span class="lnt"&gt;15&#10;&lt;/span&gt;&lt;span class="lnt"&gt;16&#10;&lt;/span&gt;&lt;span class="lnt"&gt;17&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;EventGroupHandle_t&lt;/span&gt; &lt;span class="n"&gt;eventgroup_handle&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define EVENTBIT_0 1&amp;lt;&amp;lt;0&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define EVENTBIT_1 1&amp;lt;&amp;lt;1&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;eventgroup_handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;xEventGroupCreate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="n"&gt;KEY0_PRES&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;xEventGroupSetBits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eventgroup_handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;EVENTBIT_0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="n"&gt;KEY1_PRES&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;xEventGroupSetBits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eventgroup_handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;EVENTBIT_1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;event_bit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;xEventGroupWaitBits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eventgroup_handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;EVENTBIT_0&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;EVENTBIT_1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;pdTRUE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;pdFALSE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;portMAX_DELAY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;等待到的事件标志位值:%#x&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;event_bit&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h1 id="十七任务通知"&gt;&lt;a href="#%e5%8d%81%e4%b8%83%e4%bb%bb%e5%8a%a1%e9%80%9a%e7%9f%a5" class="header-anchor"&gt;&lt;/a&gt;十七、任务通知&#13;&#10;&lt;/h1&gt;&lt;h2 id="1简介-3"&gt;&lt;a href="#1%e7%ae%80%e4%bb%8b-3" class="header-anchor"&gt;&lt;/a&gt;1.简介&#13;&#10;&lt;/h2&gt;&lt;p&gt;任务通知：用来通知任务，任务控制块中的结构体成员变量 ulNotifiedValue 就是这个通&lt;/p&gt;&#10;&lt;p&gt;知值&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;为什么还要这个？&lt;/strong&gt;&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;使用&lt;strong&gt;任务通知&lt;/strong&gt;时，任务结构体就包含了内部对象，可以直接接收别人发过来的&lt;strong&gt;通知&lt;/strong&gt;&#10;&lt;img alt="在这里插入图片描述" class="gallery-image" data-flex-basis="871px" data-flex-grow="363" height="196" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/csdn-826666d0048549709d41c331ad93a2b4.png" width="712"&gt;&lt;/li&gt;&#10;&lt;li&gt;使用&lt;strong&gt;队列、信号量、事件标志组&lt;/strong&gt;时都需另外创建一个结构体，通过中间的结构体进行简介通信&#10;&lt;img alt="在这里插入图片描述" class="gallery-image" data-flex-basis="955px" data-flex-grow="398" height="178" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/csdn-7865c42904614928b03cb5f96b1c92f5.png" width="709"&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;发送端修改接收端任务控制块中结构体变量：ulNotifiedValue&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;任务通知值的更新方式&lt;/strong&gt;&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;覆盖或不覆盖接受任务的通知值（队列）&lt;/li&gt;&#10;&lt;li&gt;更新接收任务通知值的一个过多个 bit（事件标志组）&lt;/li&gt;&#10;&lt;li&gt;增加接收任务的通知值（信号量）&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;但只能在一些场合替代&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;优劣势&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;优势：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;效率高：使用任务通知向任务发送事件或数据比使用队列、事件标志组或信号量快&lt;/li&gt;&#10;&lt;li&gt;使用内存更小：使用其他方法时都要先创建对应的结构体，使用任务通知时无需&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;劣势：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;无法发送数据给 ISR（中断服务函数）：ISR 没有任务结构体，因此无法给 ISR 发送数据，但 ISR可以使用任务通知的功能发送数据给任务&lt;/li&gt;&#10;&lt;li&gt;无法广播给多个任务：任务通知只能是被指定的一个任务接收并处理&lt;/li&gt;&#10;&lt;li&gt;无法缓存多个数据：任务通知是通过更新任务通知值来发送数据的，任务结构体中只有一个任务通知值，只能保持一个数据&lt;/li&gt;&#10;&lt;li&gt;发送受阻不支持阻塞：发送方无法进入阻塞状态等待&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="2任务通知值和通知状态"&gt;&lt;a href="#2%e4%bb%bb%e5%8a%a1%e9%80%9a%e7%9f%a5%e5%80%bc%e5%92%8c%e9%80%9a%e7%9f%a5%e7%8a%b6%e6%80%81" class="header-anchor"&gt;&lt;/a&gt;2.任务通知值和通知状态&#13;&#10;&lt;/h2&gt;&lt;p&gt;任务的任务控制块中，有两个结构体成员变量就是任务通知相关的&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;tskTaskControlBlock&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;...&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="cp"&gt;#if(configUSE_TASK_NOTIFICATIONS == 1)&#9;&lt;/span&gt;&lt;span class="c1"&gt;//打开这个宏&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;volatile&lt;/span&gt; &lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;ulNotifiedValue&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;configTASK_NOTIFICATION_ARRAY_ENTRIES&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&#9;&lt;span class="c1"&gt;//通知值&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;volatile&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;ucNotifyState&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;configTASK_NOTIFICATION_ARRAY_ENTRIES&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&#9;&#9;&lt;span class="c1"&gt;//通知状态&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;endif&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;...&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="n"&gt;tskTCB&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define configTASK_NOTIFICATION_ARRAY_ENTRIES 1&#9;&lt;/span&gt;&lt;span class="c1"&gt;//定义任务通知数组的大小，默认为1&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;任务通知值ulNotifiedValue&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;更新方式：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;计数值（数值累加，类似信号量）&lt;/li&gt;&#10;&lt;li&gt;相应位置1（类似事件标志组）&lt;/li&gt;&#10;&lt;li&gt;任意数（支持覆写不覆写，类似队列）&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;任务通知状态ucNotifyState&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;三种取值：&lt;/p&gt;&#10;&lt;p&gt;#define taskNOT_WAITING_NOTIFICATION ((uint8_t)0)&#9;&#9;//任务未等待通知&#10;#define taskWAITING_NOTIFICATION &#9; ((uint8_t)1)&#9;&#9;//任务在等待通知&#10;#define taskNOTIFICATION_RECEIVED ((uint8_t)2)&#9;&#9;//任务在等待接收&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;未等待通知：任务通知默认的初始化状态（事不关己，高高挂起）&lt;/li&gt;&#10;&lt;li&gt;等待通知：接收方已经准备好了（调用了&lt;strong&gt;接收&lt;/strong&gt;任务通知函数），等待发送方给个通知&lt;/li&gt;&#10;&lt;li&gt;等待接收：发送方已经发送出去（调用了&lt;strong&gt;发送&lt;/strong&gt;任务通知函数），等待接收方接收&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="3任务通知api函数"&gt;&lt;a href="#3%e4%bb%bb%e5%8a%a1%e9%80%9a%e7%9f%a5api%e5%87%bd%e6%95%b0" class="header-anchor"&gt;&lt;/a&gt;3.任务通知API函数&#13;&#10;&lt;/h2&gt;&lt;p&gt;有发送和接收，发送可在任务和中断中，接收只能在任务（因为中断没TCB）&lt;/p&gt;&#10;&lt;h3 id="31发送"&gt;&lt;a href="#31%e5%8f%91%e9%80%81" class="header-anchor"&gt;&lt;/a&gt;3.1发送&#13;&#10;&lt;/h3&gt;&lt;p&gt;&lt;img alt="image-20250806194128769" class="gallery-image" data-flex-basis="496px" data-flex-grow="207" height="342" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250806194128769.png" width="708"&gt;&lt;/p&gt;&#10;&lt;p&gt;函数原型&lt;/p&gt;&#10;&lt;img src="images/image-20250806195030350.png" alt="image-20250806195030350" style="zoom:67%;" /&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;span class="lnt"&gt;15&#10;&lt;/span&gt;&lt;span class="lnt"&gt;16&#10;&lt;/span&gt;&lt;span class="lnt"&gt;17&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;BaseType_t&lt;/span&gt; &lt;span class="nf"&gt;xTaskGenericNotify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TaskHandle_t&lt;/span&gt; &lt;span class="n"&gt;xTaskToNotify&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &#9;&#9;&#9;&#9; &lt;span class="n"&gt;UBaseType_t&lt;/span&gt; &lt;span class="n"&gt;uxIndexToNotify&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&#9; &lt;span class="kt"&gt;uint32_t&lt;/span&gt; &#9; &lt;span class="n"&gt;ulValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&#9; &lt;span class="n"&gt;eNotifyAction&lt;/span&gt; &lt;span class="n"&gt;eAction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&#9; &lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;pulPreviousNotificationValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define xTaskNotify(xTaskToNotify, ulValue, eAction) &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="nf"&gt;xTaskGenericNotify&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;xTaskToNotify&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tskDEFAULT_INDEX_TO_NOTIFY&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&#9;&#9;&#9; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ulValue&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eAction&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &#9;&#9;&#9;&#9; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define xTaskNotifyAndQuery(xTaskToNotify, ulValue, eAction, pulPreviousNotifyValue) &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &#9;&lt;span class="nf"&gt;xTaskGenericNotify&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;xTaskToNotify&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tskDEFAULT_INDEX_TO_NOTIFY&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &#9;&#9;&#9;&#9;&#9; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ulValue&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eAction&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pulPreviousNotifyValue&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &#9;&#9;&#9; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define xTaskNotifyGive(xTaskToNotify) &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &#9; &#9;&lt;span class="nf"&gt;xTaskGenericNotify&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;xTaskToNotify&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tskDEFAULT_INDEX_TO_NOTIFY&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &#9;&#9;&#9;&#9; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;eIncrement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;其中通知方式（通知值更新方式）eNotifyAction&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;span class="lnt"&gt;7&#10;&lt;/span&gt;&lt;span class="lnt"&gt;8&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;enum&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;eNoAction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &#9;&#9;&#9;&#9;&lt;span class="cm"&gt;/* 无操作 */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;eSetBits&lt;/span&gt; &#9;&#9;&#9;&#9;&#9;&lt;span class="cm"&gt;/* 更新指定 bit */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;eIncrement&lt;/span&gt; &#9;&#9;&#9;&#9;&#9;&lt;span class="cm"&gt;/* 通知值加一 */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;eSetValueWithOverwrite&lt;/span&gt; &#9;&#9;&lt;span class="cm"&gt;/* 覆写的方式更新通知值*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;eSetValueWithoutOverwrite&lt;/span&gt; &#9;&lt;span class="cm"&gt;/* 不覆写通知值 */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;eNotifyAction&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h3 id="32接收"&gt;&lt;a href="#32%e6%8e%a5%e6%94%b6" class="header-anchor"&gt;&lt;/a&gt;3.2接收&#13;&#10;&lt;/h3&gt;&lt;img src="images/image-20250806195719064.png" alt="image-20250806195719064" style="zoom:67%;" /&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;当任务通知用作与信号量时，使用函数获取信号量：&lt;code&gt;ulTaskNotifyTake( )&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;当任务通知用作与事件标志组或队列时，使用此函数来获取：&lt;code&gt;xTaskNotifyWait( )&lt;/code&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="321ultasknotifytake"&gt;&lt;a href="#321ultasknotifytake" class="header-anchor"&gt;&lt;/a&gt;3.2.1ulTaskNotifyTake&#13;&#10;&lt;/h4&gt;&lt;p&gt;ulTaskNotifyTake( xClearCountOnExit , xTicksToWait )&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;#define ulTaskNotifyTake(xClearCountOnExit, xTicksToWait) &#10;&#9;&#9;ulTaskGenericNotifyTake((tskDEFAULT_INDEX_TO_NOTIFY), &#10;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;(xClearCountOnExit), &#10;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;(xTicksToWait)) &#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;原型&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;uint32_t ulTaskGenericNotifyTake(UBaseType_t uxIndexToWaitOn, &#10;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9; BaseType_t xClearCountOnExit, &#10;&#9;&#9;&#9;&#9;&#9;&#9;&#9; &#9; TickType_t xTicksToWait); &#10;&lt;/code&gt;&lt;/pre&gt;&lt;img src="images/image-20250806201907259.png" alt="image-20250806201907259" style="zoom:67%;" /&gt;&#10;&lt;p&gt;通知值清零模拟二值信号量，通知值减一模拟计数型信号量&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;3.2.2xTaskNotifyWait&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;此函数用于等待任务通知通知值中的指定比特位被置 1，此函数可以在等待前和成功等待到任务通知通知值中的指定比特位被置 1 后清零指定比特位，并且还能获取等待超时后任务通知的通知值。&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;#define xTaskNotifyWait(ulBitsToClearOnEntry, &#10;&#9;&#9;&#9; ulBitsToClearOnExit, &#10;&#9;&#9;&#9; pulNotificationValue, &#10;&#9;&#9;&#9; xTicksToWait) &#10; &#9; xTaskGenericNotifyWait(tskDEFAULT_INDEX_TO_NOTIFY, &#10;&#9;&#9;&#9;&#9;&#9; (ulBitsToClearOnEntry), &#10;&#9;&#9;&#9;&#9;&#9; (ulBitsToClearOnExit), &#10;&#9;&#9;&#9;&#9;&#9; (pulNotificationValue), &#10;&#9;&#9;&#9;&#9;&#9; (xTicksToWait)) &#10;&lt;/code&gt;&lt;/pre&gt;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;形参&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;描述&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;uxIndexToWaitOn&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;等待的任务通知索引（任务通知数组下标）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;ulBitsToClearOnEntry&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;进入等待前，把任务通知值的哪些位清 0（旧值对应位清零）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;ulBitsToClearOnExit&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;等待成功后，把任务通知值的哪些位清 0（新值对应位清零）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;pulNotificationValue&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;用于取出当时的 32 位通知值；若不需要，可设为 NULL&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;xTicksToWait&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;最大阻塞等待时间（以系统节拍为单位）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;返回值&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;描述&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;pdTRUE&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;等待任务通知成功（已满足等待条件）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;pdFALSE&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;等待任务通知失败（超时或被中断）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="4任务通知模拟信号量"&gt;&lt;a href="#4%e4%bb%bb%e5%8a%a1%e9%80%9a%e7%9f%a5%e6%a8%a1%e6%8b%9f%e4%bf%a1%e5%8f%b7%e9%87%8f" class="header-anchor"&gt;&lt;/a&gt;4.任务通知模拟信号量&#13;&#10;&lt;/h2&gt;&lt;p&gt;模拟二值信号量&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;span class="lnt"&gt;15&#10;&lt;/span&gt;&lt;span class="lnt"&gt;16&#10;&lt;/span&gt;&lt;span class="lnt"&gt;17&#10;&lt;/span&gt;&lt;span class="lnt"&gt;18&#10;&lt;/span&gt;&lt;span class="lnt"&gt;19&#10;&lt;/span&gt;&lt;span class="lnt"&gt;20&#10;&lt;/span&gt;&lt;span class="lnt"&gt;21&#10;&lt;/span&gt;&lt;span class="lnt"&gt;22&#10;&lt;/span&gt;&lt;span class="lnt"&gt;23&#10;&lt;/span&gt;&lt;span class="lnt"&gt;24&#10;&lt;/span&gt;&lt;span class="lnt"&gt;25&#10;&lt;/span&gt;&lt;span class="lnt"&gt;26&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;task1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;pvParamenters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;key_scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="n"&gt;KEY0_PRES&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;任务通知模拟二值信号量释放&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;xTaskNotifyGive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task2_handle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;task2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;pvParamenters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;rev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;rev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ulTaskNotifyTake&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pdTRUE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;portMAX_DELAY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rev&lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;接受任务通知成功,获取模拟二值信号量&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;模拟计数型信号量&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;span class="lnt"&gt;15&#10;&lt;/span&gt;&lt;span class="lnt"&gt;16&#10;&lt;/span&gt;&lt;span class="lnt"&gt;17&#10;&lt;/span&gt;&lt;span class="lnt"&gt;18&#10;&lt;/span&gt;&lt;span class="lnt"&gt;19&#10;&lt;/span&gt;&lt;span class="lnt"&gt;20&#10;&lt;/span&gt;&lt;span class="lnt"&gt;21&#10;&lt;/span&gt;&lt;span class="lnt"&gt;22&#10;&lt;/span&gt;&lt;span class="lnt"&gt;23&#10;&lt;/span&gt;&lt;span class="lnt"&gt;24&#10;&lt;/span&gt;&lt;span class="lnt"&gt;25&#10;&lt;/span&gt;&lt;span class="lnt"&gt;26&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;task1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;pvParamenters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;key_scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="n"&gt;KEY0_PRES&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;任务通知模拟计数型信号量释放&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;xTaskNotifyGive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task2_handle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;task2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;pvParamenters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;rev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;rev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ulTaskNotifyTake&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pdFALSE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;portMAX_DELAY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rev&lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;接受任务通知成功,模拟获取计数型信号量,rev:%d&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;rev&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;vTaskDelay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h2 id="5任务通知模拟消息邮箱类似队列"&gt;&lt;a href="#5%e4%bb%bb%e5%8a%a1%e9%80%9a%e7%9f%a5%e6%a8%a1%e6%8b%9f%e6%b6%88%e6%81%af%e9%82%ae%e7%ae%b1%e7%b1%bb%e4%bc%bc%e9%98%9f%e5%88%97" class="header-anchor"&gt;&lt;/a&gt;5.任务通知模拟消息邮箱（类似队列）&#13;&#10;&lt;/h2&gt;&lt;p&gt;消息邮箱其实就是长度为1的队列&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;span class="lnt"&gt;15&#10;&lt;/span&gt;&lt;span class="lnt"&gt;16&#10;&lt;/span&gt;&lt;span class="lnt"&gt;17&#10;&lt;/span&gt;&lt;span class="lnt"&gt;18&#10;&lt;/span&gt;&lt;span class="lnt"&gt;19&#10;&lt;/span&gt;&lt;span class="lnt"&gt;20&#10;&lt;/span&gt;&lt;span class="lnt"&gt;21&#10;&lt;/span&gt;&lt;span class="lnt"&gt;22&#10;&lt;/span&gt;&lt;span class="lnt"&gt;23&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;task1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pvParamenters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;key_scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task2_handle&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;任务通知模拟消息邮箱发送,发送的键值为:%d&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;xTaskNotify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task2_handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;eSetValueWithOverwrite&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;vTaskDelay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;task2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pvParamenters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;notify_val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;xTaskNotifyWait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xFFFFFFFF&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;notify_val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;portMAX_DELAY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;接受到的通知值为:%d&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;notify_val&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h2 id="6任务通知模拟事件标志组"&gt;&lt;a href="#6%e4%bb%bb%e5%8a%a1%e9%80%9a%e7%9f%a5%e6%a8%a1%e6%8b%9f%e4%ba%8b%e4%bb%b6%e6%a0%87%e5%bf%97%e7%bb%84" class="header-anchor"&gt;&lt;/a&gt;6.任务通知模拟事件标志组&#13;&#10;&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;span class="lnt"&gt;15&#10;&lt;/span&gt;&lt;span class="lnt"&gt;16&#10;&lt;/span&gt;&lt;span class="lnt"&gt;17&#10;&lt;/span&gt;&lt;span class="lnt"&gt;18&#10;&lt;/span&gt;&lt;span class="lnt"&gt;19&#10;&lt;/span&gt;&lt;span class="lnt"&gt;20&#10;&lt;/span&gt;&lt;span class="lnt"&gt;21&#10;&lt;/span&gt;&lt;span class="lnt"&gt;22&#10;&lt;/span&gt;&lt;span class="lnt"&gt;23&#10;&lt;/span&gt;&lt;span class="lnt"&gt;24&#10;&lt;/span&gt;&lt;span class="lnt"&gt;25&#10;&lt;/span&gt;&lt;span class="lnt"&gt;26&#10;&lt;/span&gt;&lt;span class="lnt"&gt;27&#10;&lt;/span&gt;&lt;span class="lnt"&gt;28&#10;&lt;/span&gt;&lt;span class="lnt"&gt;29&#10;&lt;/span&gt;&lt;span class="lnt"&gt;30&#10;&lt;/span&gt;&lt;span class="lnt"&gt;31&#10;&lt;/span&gt;&lt;span class="lnt"&gt;32&#10;&lt;/span&gt;&lt;span class="lnt"&gt;33&#10;&lt;/span&gt;&lt;span class="lnt"&gt;34&#10;&lt;/span&gt;&lt;span class="lnt"&gt;35&#10;&lt;/span&gt;&lt;span class="lnt"&gt;36&#10;&lt;/span&gt;&lt;span class="lnt"&gt;37&#10;&lt;/span&gt;&lt;span class="lnt"&gt;38&#10;&lt;/span&gt;&lt;span class="lnt"&gt;39&#10;&lt;/span&gt;&lt;span class="lnt"&gt;40&#10;&lt;/span&gt;&lt;span class="lnt"&gt;41&#10;&lt;/span&gt;&lt;span class="lnt"&gt;42&#10;&lt;/span&gt;&lt;span class="lnt"&gt;43&#10;&lt;/span&gt;&lt;span class="lnt"&gt;44&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define EVENTBIT_0 1&amp;lt;&amp;lt;0&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define EVENTBIT_1 1&amp;lt;&amp;lt;1&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;task1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pvParamenters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;key_scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="n"&gt;KEY0_PRES&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;更新bit0位置1&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;xTaskNotify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task2_handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;EVENTBIT_0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;eSetBits&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="n"&gt;KEY1_PRES&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;更新bit1位置1&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;xTaskNotify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task2_handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;EVENTBIT_1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;eSetBits&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;vTaskDelay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;task2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pvParamenters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;notify_val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;event_bit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;xTaskNotifyWait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mh"&gt;0xFFFFFFFF&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;notify_val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;portMAX_DELAY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;notify_val&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;EVENTBIT_0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;event_bit&lt;/span&gt;&lt;span class="o"&gt;|=&lt;/span&gt;&lt;span class="n"&gt;EVENTBIT_0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;notify_val&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;EVENTBIT_1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;event_bit&lt;/span&gt;&lt;span class="o"&gt;|=&lt;/span&gt;&lt;span class="n"&gt;EVENTBIT_1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event_bit&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EVENTBIT_0&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;EVENTBIT_1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;任务通知模拟事件标志组接收成功&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;event_bit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h1 id="十八软件定时器"&gt;&lt;a href="#%e5%8d%81%e5%85%ab%e8%bd%af%e4%bb%b6%e5%ae%9a%e6%97%b6%e5%99%a8" class="header-anchor"&gt;&lt;/a&gt;十八、软件定时器&#13;&#10;&lt;/h1&gt;&lt;p&gt;&lt;img alt="image-20250806205006783" class="gallery-image" data-flex-basis="577px" data-flex-grow="240" height="346" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/image-20250806205006783.png" srcset="https://zeseanblog.top/p/freertos/images/image-20250806205006783_hu_62851451dbd3d8fc.png 800w, https://zeseanblog.top/p/freertos/images/image-20250806205006783.png 833w" width="833"&gt;&lt;/p&gt;&#10;&lt;h2 id="1简介-4"&gt;&lt;a href="#1%e7%ae%80%e4%bb%8b-4" class="header-anchor"&gt;&lt;/a&gt;1.简介&#13;&#10;&lt;/h2&gt;&lt;p&gt;定时器：指定时刻开始，经过指定时间，触发超时事件，用户可自定义周期&lt;/p&gt;&#10;&lt;p&gt;硬件定时器：芯片自带定时器，精度高，通过定时器中断，在中断服务函数处理&lt;/p&gt;&#10;&lt;p&gt;软件定时器：定时功能的软件，可设定定时周期，超时调用回调函数，在回调函数处理&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;软件定时器优缺点&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;优点：硬件定时器有限，而软件定时器理论更多；使用简单&lt;/p&gt;&#10;&lt;p&gt;缺点：精度低，对于高精度要求，不使用&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;FreeRTOS软件定时器特点&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;可裁剪：configUSE_TIMERS 配置项配置成 1&lt;/p&gt;&#10;&lt;p&gt;支持单次和周期&lt;/p&gt;&#10;&lt;p&gt;注：软件定时器的超时回调函数是由软件定时器服务任务调用的，软件定时器的超时回调函数本身不是任务，因此不能在该回调函数中使用可能会导致任务阻塞的 API 函数&lt;/p&gt;&#10;&lt;p&gt;软件定时器服务任务：vTaskStartScheduler()中会创建&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;软件定时器命令队列&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;FreeRTOS 提供了许多软件定时器相关的 API 函数，这些 API 函数大多是往定时器的队列中写入消息（发送命令），这个队列叫做软件定时器命令队列。这个队列控制软件定时器&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="在这里插入图片描述" class="gallery-image" data-flex-basis="664px" data-flex-grow="276" height="320" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/csdn-dec1d4afafd944af9c3d72484668e479.png" srcset="https://zeseanblog.top/p/freertos/images/csdn-dec1d4afafd944af9c3d72484668e479_hu_d4a148b3eebc8b5c.png 800w, https://zeseanblog.top/p/freertos/images/csdn-dec1d4afafd944af9c3d72484668e479.png 886w" width="886"&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;软件定时器相关配置&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;configUSE_TIMERS配置为1&lt;/p&gt;&#10;&lt;p&gt;启动任务调度器时，会自动创建软件定时器的服务 / 守护任务&lt;code&gt;prvTimerTask( );&lt;/code&gt;&lt;/p&gt;&#10;&lt;p&gt;软件定时器服务任务的优先级为&lt;code&gt;configTIMER_TASK_PRIORITY = 31;&lt;/code&gt;&lt;/p&gt;&#10;&lt;p&gt;定时器的命令队列长度为&lt;code&gt;configTIMER_QUEUE_LENGTH = 5;&lt;/code&gt;&lt;/p&gt;&#10;&lt;p&gt;注：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;服务任务服务于多个定时器，因此定时器的回调函数不能影响其他定时器&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;回调函数要尽快实行，不能进入阻塞状态，既不能调用那些会阻塞任务的 API 函数，如&lt;code&gt;vTaskDelay( );&lt;/code&gt;&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;访问队列或者信号量的非零阻塞时间的 API 函数也不能调用&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;软件定时器状态&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;休眠态、运行态&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;单次定时器和周期定时器&lt;/strong&gt;&lt;/p&gt;&#10;&lt;img src="images/csdn-1a24e562ecc04dc6b02c8e997b73fb93.png" alt="在这里插入图片描述" style="zoom:67%;" /&gt;&#10;&lt;img src="images/csdn-4fe5bfabfcf346cea4ccaa38d865be8f.png" alt="在这里插入图片描述" style="zoom:67%;" /&gt;&#10;&lt;h2 id="2软件定时器结构体"&gt;&lt;a href="#2%e8%bd%af%e4%bb%b6%e5%ae%9a%e6%97%b6%e5%99%a8%e7%bb%93%e6%9e%84%e4%bd%93" class="header-anchor"&gt;&lt;/a&gt;2.软件定时器结构体&#13;&#10;&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;pcTimerName&lt;/span&gt; &#9;&#9;&#9;&#9;&#9;&lt;span class="cm"&gt;/* 软件定时器名字 */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;ListItem_t&lt;/span&gt; &lt;span class="n"&gt;xTimerListItem&lt;/span&gt; &#9;&#9;&#9;&#9;&#9;&lt;span class="cm"&gt;/* 软件定时器列表项 */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;TickType_t&lt;/span&gt; &lt;span class="n"&gt;xTimerPeriodInTicks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &#9;&#9;&#9;&lt;span class="cm"&gt;/* 软件定时器的周期*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;pvTimerID&lt;/span&gt; &#9;&#9;&#9;&#9;&#9;&#9;&#9;&lt;span class="cm"&gt;/* 软件定时器的 ID */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;TimerCallbackFunction_t&lt;/span&gt; &lt;span class="n"&gt;pxCallbackFunction&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* 软件定时器的回调函数*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="cp"&gt;#if ( configUSE_TRACE_FACILITY == 1 )&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="n"&gt;UBaseType_t&lt;/span&gt; &lt;span class="n"&gt;uxTimerNumber&lt;/span&gt; &#9;&#9;&#9;&#9;&lt;span class="cm"&gt;/* 软件定时器编号调试用*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="cp"&gt;#endif&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;ucStatus&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &#9;&#9;&#9;&#9;&#9;&#9;&#9;&lt;span class="cm"&gt;/* 软件定时器的状态 */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;xTIMER&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h2 id="3软件定时器相关api"&gt;&lt;a href="#3%e8%bd%af%e4%bb%b6%e5%ae%9a%e6%97%b6%e5%99%a8%e7%9b%b8%e5%85%b3api" class="header-anchor"&gt;&lt;/a&gt;3.软件定时器相关API&#13;&#10;&lt;/h2&gt;&lt;img src="images/image-20250806211339288.png" alt="image-20250806211339288" style="zoom:50%;" /&gt;&#10;&lt;h3 id="31创建xtimercreate"&gt;&lt;a href="#31%e5%88%9b%e5%bb%baxtimercreate" class="header-anchor"&gt;&lt;/a&gt;3.1创建xTimerCreate&#13;&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;TimerHandle_t&lt;/span&gt; &lt;span class="nf"&gt;xTimerCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &#9;&lt;span class="n"&gt;pcTimerName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&#9;&#9;&#9; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;TickType_t&lt;/span&gt; &#9; &lt;span class="n"&gt;xTimerPeriodInTicks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&#9;&#9;&#9; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;UBaseType_t&lt;/span&gt; &#9;&#9;&lt;span class="n"&gt;uxAutoReload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&#9;&#9;&#9; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &#9;&#9;&lt;span class="n"&gt;pvTimerID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&#9;&#9;&#9; &lt;span class="n"&gt;TimerCallbackFunction_t&lt;/span&gt; &lt;span class="n"&gt;pxCallbackFunction&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;形参&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;描述&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;pcTimerName&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;软件定时器名称（字符串）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;xTimerPeriodInTicks&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;定时周期，以系统时钟节拍（ticks）为单位&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;uxAutoReload&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;定时器模式：&lt;br&gt;&lt;strong&gt;pdTRUE&lt;/strong&gt; = 周期定时器（重复触发）&lt;br&gt;&lt;strong&gt;pdFALSE&lt;/strong&gt; = 单次定时器（触发一次后停止）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;pvTimerID&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;用户自定义 ID，可用于多个定时器共用同一回调函数时区分实例&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;pxCallbackFunction&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;定时器超时时的回调函数指针&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;返回值&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;描述&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;NULL&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;软件定时器创建失败&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;非 NULL 句柄&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;软件定时器创建成功，返回该定时器的句柄&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;创建例子&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;timer1_handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;xTimerCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;timer1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;pdFALSE&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;timer1_callback&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;timer2_handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;xTimerCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;timer2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;pdTRUE&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;timer2_callback&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h3 id="32开启xtimerstart"&gt;&lt;a href="#32%e5%bc%80%e5%90%afxtimerstart" class="header-anchor"&gt;&lt;/a&gt;3.2开启xTimerStart&#13;&#10;&lt;/h3&gt;&lt;p&gt;BaseType_t xTimerStart( TimerHandle_t xTimer,&#10;const TickType_t xTicksToWait );&lt;/p&gt;&#10;&lt;p&gt;参数：xTimer 待开启的软件定时器的句柄&#10;xTickToWait 发送命令到软件定时器命令队列的最大等待时间&lt;/p&gt;&#10;&lt;p&gt;返回pdPASS，pdFAIL&lt;/p&gt;&#10;&lt;h3 id="33停止xtimerstop"&gt;&lt;a href="#33%e5%81%9c%e6%ad%a2xtimerstop" class="header-anchor"&gt;&lt;/a&gt;3.3停止xTimerStop&#13;&#10;&lt;/h3&gt;&lt;p&gt;BaseType_t xTimerStop( TimerHandle_t xTimer,&#10;const TickType_t xTicksToWait);&lt;/p&gt;&#10;&lt;p&gt;参数：xTimer 待停止的软件定时器的句柄&#10;xTickToWait 发送命令到软件定时器命令队列的最大等待时间&lt;/p&gt;&#10;&lt;p&gt;返回pdPASS，pdFAIL&lt;/p&gt;&#10;&lt;h3 id="34复位xtimerreset"&gt;&lt;a href="#34%e5%a4%8d%e4%bd%8dxtimerreset" class="header-anchor"&gt;&lt;/a&gt;3.4复位xTimerReset&#13;&#10;&lt;/h3&gt;&lt;p&gt;使软件定时器的重新开启定时&lt;/p&gt;&#10;&lt;p&gt;BaseType_t xTimerReset( TimerHandle_t xTimer,&#10;const TickType_t xTicksToWait);&lt;/p&gt;&#10;&lt;p&gt;参数：xTimer 待复位的软件定时器的句柄&#10;xTickToWait 发送命令到软件定时器命令队列的最大等待时间&lt;/p&gt;&#10;&lt;p&gt;返回pdPASS，pdFAIL&lt;/p&gt;&#10;&lt;h3 id="35更改超时时间xtimerchangeperiod"&gt;&lt;a href="#35%e6%9b%b4%e6%94%b9%e8%b6%85%e6%97%b6%e6%97%b6%e9%97%b4xtimerchangeperiod" class="header-anchor"&gt;&lt;/a&gt;3.5更改超时时间xTimerChangePeriod&#13;&#10;&lt;/h3&gt;&lt;p&gt;BaseType_t xTimerChangePeriod( TimerHandle_t xTimer,&#10;const TickType_t xNewPeriod,&#10;const TickType_t xTicksToWait);&lt;/p&gt;&#10;&lt;p&gt;参数：xTimer 待更新的软件定时器的句柄&#10;xNewPeriod 新的定时超时时间，单位：系统时钟节拍&#10;xTickToWait 发送命令到软件定时器命令队列的最大等待时间&lt;/p&gt;&#10;&lt;p&gt;返回pdPASS，pdFAIL&lt;/p&gt;&#10;&lt;h3 id="示例-2"&gt;&lt;a href="#%e7%a4%ba%e4%be%8b-2" class="header-anchor"&gt;&lt;/a&gt;示例&#13;&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;span class="lnt"&gt;15&#10;&lt;/span&gt;&lt;span class="lnt"&gt;16&#10;&lt;/span&gt;&lt;span class="lnt"&gt;17&#10;&lt;/span&gt;&lt;span class="lnt"&gt;18&#10;&lt;/span&gt;&lt;span class="lnt"&gt;19&#10;&lt;/span&gt;&lt;span class="lnt"&gt;20&#10;&lt;/span&gt;&lt;span class="lnt"&gt;21&#10;&lt;/span&gt;&lt;span class="lnt"&gt;22&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;TimerHandle_t&lt;/span&gt; &lt;span class="n"&gt;timer1_handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="cm"&gt;/*单次定时器*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;TimerHandle_t&lt;/span&gt; &lt;span class="n"&gt;timer2_handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="cm"&gt;/*周期定时器*/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;timer1_callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TimerHandle_t&lt;/span&gt; &lt;span class="n"&gt;pxTimer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;timer2_callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TimerHandle_t&lt;/span&gt; &lt;span class="n"&gt;pxTimer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;timer1_handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;xTimerCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;timer1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;pdFALSE&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;timer1_callback&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;timer2_handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;xTimerCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;timer2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;pdTRUE&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;timer2_callback&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;xTimerStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timer2_handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;xTimerStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timer1_handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;timer1_callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TimerHandle_t&lt;/span&gt; &lt;span class="n"&gt;pxTimer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;timer1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Timer1的运行次数:%d&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;timer1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;timer2_callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TimerHandle_t&lt;/span&gt; &lt;span class="n"&gt;pxTimer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;timer2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Timer2的运行次数:%d&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;timer2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h1 id="十九tickless低功耗模式"&gt;&lt;a href="#%e5%8d%81%e4%b9%9dtickless%e4%bd%8e%e5%8a%9f%e8%80%97%e6%a8%a1%e5%bc%8f" class="header-anchor"&gt;&lt;/a&gt;十九、Tickless低功耗模式&#13;&#10;&lt;/h1&gt;&lt;h2 id="1低功耗模式"&gt;&lt;a href="#1%e4%bd%8e%e5%8a%9f%e8%80%97%e6%a8%a1%e5%bc%8f" class="header-anchor"&gt;&lt;/a&gt;1.低功耗模式&#13;&#10;&lt;/h2&gt;&lt;p&gt;STM32提供集中低功耗，睡眠，停止，待机&lt;/p&gt;&#10;&lt;p&gt;FreeRTOS也提供Tickless低功耗模式，通过动态调整SysTick 减少不必要的 CPU 唤醒，从而降低功耗&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="在这里插入图片描述" class="gallery-image" data-flex-basis="890px" data-flex-grow="370" height="165" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://zeseanblog.top/p/freertos/images/csdn-513b937e09684f76af4d3b4f8a5a0124.png" width="612"&gt;&lt;/p&gt;&#10;&lt;p&gt;为了降低功耗，又不影响系统运行，可以在本该空闲任务执行期间，让 MCU 进入相应的低功耗模式；当其他任务准备运行的时候，唤醒 MCU 退出低功耗模式，但是进入低功耗之后，多久唤醒，下一个要运行的任务如何被准确唤醒？任何中断均可唤醒 MCU，若滴答定时器频繁中断则会影响低功耗的效果。这些问题可以这样解决：&lt;/p&gt;&#10;&lt;p&gt;将滴答定时器的中断周期修改为低功耗运行时间&#10;推出低功耗之后，补上系统时钟节拍数&lt;/p&gt;&#10;&lt;h2 id="2相关配置"&gt;&lt;a href="#2%e7%9b%b8%e5%85%b3%e9%85%8d%e7%bd%ae" class="header-anchor"&gt;&lt;/a&gt;2.相关配置&#13;&#10;&lt;/h2&gt;&lt;p&gt;使能低功耗 Tickless 模式：configUSE_TICKLESS_IDLE&#10;定义系统进入相应低功耗模式的最短时长：configEXPECTED_IDLE_TIME_BEFORE_SLEEP&#10;定义需要在系统进入低功耗模式之前执行的事务，例如：进入低功耗之前关闭外设时钟，以降低功耗：configPRE_SLEEP_PROCESSING(x)，需要自己在 FreeRTOSconfig.h 里面自己定义&#10;定义需要在系统退出低功耗模式之后执行的事务，例如：退出低功耗之后开启被关闭的外设时钟，使系统能够正常运行：configPOST_SLEEP_PROCESSING(x)，需要自己在 FreeRTOSconfig.h 里面自己定义&lt;/p&gt;&#10;&lt;h2 id="3实现"&gt;&lt;a href="#3%e5%ae%9e%e7%8e%b0" class="header-anchor"&gt;&lt;/a&gt;3.实现&#13;&#10;&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;span class="lnt"&gt;15&#10;&lt;/span&gt;&lt;span class="lnt"&gt;16&#10;&lt;/span&gt;&lt;span class="lnt"&gt;17&#10;&lt;/span&gt;&lt;span class="lnt"&gt;18&#10;&lt;/span&gt;&lt;span class="lnt"&gt;19&#10;&lt;/span&gt;&lt;span class="lnt"&gt;20&#10;&lt;/span&gt;&lt;span class="lnt"&gt;21&#10;&lt;/span&gt;&lt;span class="lnt"&gt;22&#10;&lt;/span&gt;&lt;span class="lnt"&gt;23&#10;&lt;/span&gt;&lt;span class="lnt"&gt;24&#10;&lt;/span&gt;&lt;span class="lnt"&gt;25&#10;&lt;/span&gt;&lt;span class="lnt"&gt;26&#10;&lt;/span&gt;&lt;span class="lnt"&gt;27&#10;&lt;/span&gt;&lt;span class="lnt"&gt;28&#10;&lt;/span&gt;&lt;span class="lnt"&gt;29&#10;&lt;/span&gt;&lt;span class="lnt"&gt;30&#10;&lt;/span&gt;&lt;span class="lnt"&gt;31&#10;&lt;/span&gt;&lt;span class="lnt"&gt;32&#10;&lt;/span&gt;&lt;span class="lnt"&gt;33&#10;&lt;/span&gt;&lt;span class="lnt"&gt;34&#10;&lt;/span&gt;&lt;span class="lnt"&gt;35&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define configUSE_TICKLESS_IDLE 1 &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 2&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;//接着在 FreeRTOSconfig.h 文件中找个位置定义下面函数&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;#34;freertos_demo.h&amp;#34;&lt;/span&gt;&lt;span class="cp"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define configPRE_SLEEP_PROCESSING( x )&#9;&#9;PRE_SLEEP_PROCESSING()&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define configPOST_SLEEP_PROCESSING( x )&#9;POSR_SLEEP_PROCESSING()&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;//freertos_demo.h 文件里声明这两个函数&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;PRE_SLEEP_PROCESSING&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;POST_SLEEP_PROCESSING&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;//freertos_demo.c 文件里，入口函数上面定义&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;//进入低功耗模式前要关闭的事情&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;PRE_SLEEP_PROCESSING&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="nf"&gt;__HAL_RCC_GPIOA_CLK_DISABLE&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="nf"&gt;__HAL_RCC_GPIOB_CLK_DISABLE&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="nf"&gt;__HAL_RCC_GPIOC_CLK_DISABLE&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="nf"&gt;__HAL_RCC_GPIOD_CLK_DISABLE&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="nf"&gt;__HAL_RCC_GPIOE_CLK_DISABLE&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="nf"&gt;__HAL_RCC_GPIOF_CLK_DISABLE&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="nf"&gt;__HAL_RCC_GPIOG_CLK_DISABLE&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;//退出低功耗模式后需要打开的事情&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;POST_SLEEP_PROCESSING&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="nf"&gt;__HAL_RCC_GPIOA_CLK_ENABLE&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="nf"&gt;__HAL_RCC_GPIOB_CLK_ENABLE&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="nf"&gt;__HAL_RCC_GPIOC_CLK_ENABLE&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="nf"&gt;__HAL_RCC_GPIOD_CLK_ENABLE&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="nf"&gt;__HAL_RCC_GPIOE_CLK_ENABLE&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="nf"&gt;__HAL_RCC_GPIOF_CLK_ENABLE&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="nf"&gt;__HAL_RCC_GPIOG_CLK_ENABLE&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h1 id="二十freertos内存管理"&gt;&lt;a href="#%e4%ba%8c%e5%8d%81freertos%e5%86%85%e5%ad%98%e7%ae%a1%e7%90%86" class="header-anchor"&gt;&lt;/a&gt;二十、FreeRTOS内存管理&#13;&#10;&lt;/h1&gt;&lt;h2 id="1freertos内存管理简介"&gt;&lt;a href="#1freertos%e5%86%85%e5%ad%98%e7%ae%a1%e7%90%86%e7%ae%80%e4%bb%8b" class="header-anchor"&gt;&lt;/a&gt;1.FreeRTOS内存管理简介&#13;&#10;&lt;/h2&gt;&lt;p&gt;FreeRTOS创建任务、队列、信号量等时，可用动态方法或者静态方法创建&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;动态方法：申请时FreeRTOS从内存堆中自动申请，删除对象时自动释放&lt;/li&gt;&#10;&lt;li&gt;静态方法：用户提供内存空间，但是占用的空间固定下来了，删除依旧占用&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;本节讲的是动态内存管理方式（实际是管理算法的区别heap.c）&lt;/p&gt;&#10;&lt;p&gt;freertosconfig.h中定义的宏管理内存堆的大小：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define configTOTAL_HEAP_SIZE ((size_t)(10 * 1024)) &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* FreeRTOS堆中可用的RAM总量, 单位: Byte, 无默认需定义 */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h2 id="2freertos内存管理算法"&gt;&lt;a href="#2freertos%e5%86%85%e5%ad%98%e7%ae%a1%e7%90%86%e7%ae%97%e6%b3%95" class="header-anchor"&gt;&lt;/a&gt;2.FreeRTOS内存管理算法&#13;&#10;&lt;/h2&gt;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;算法&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;优点&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;缺点&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;heap_1&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;分配简单，时间确定&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;只允许申请内存，不允许释放内存&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;heap_2&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;允许申请和释放内存&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;不能合并相邻空闲块，产生碎片，时间不定&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;heap_3&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;直接调用 C 库 malloc()/free()，实现简单（不使用）&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;速度慢、时间不定&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;heap_4&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;相邻空闲块可合并，减少碎片&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;时间不定&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;heap_5&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;支持管理&lt;strong&gt;多个非连续内存区域&lt;/strong&gt;，功能同 heap_4&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;时间不定&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h3 id="21-heap_1"&gt;&lt;a href="#21-heap_1" class="header-anchor"&gt;&lt;/a&gt;2.1 heap_1&#13;&#10;&lt;/h3&gt;&lt;p&gt;heap_1只能申请内存无法释放内存，若工程中创建好的任务、队列、信号量等不需要删除，那使用heap_1&lt;/p&gt;&#10;&lt;p&gt;heap_1分配图示：&lt;/p&gt;&#10;&lt;img src="images/image-20250806221459608.png" alt="image-20250806221459608" style="zoom:50%;" /&gt;&#10;&lt;h3 id="22-heap_2"&gt;&lt;a href="#22-heap_2" class="header-anchor"&gt;&lt;/a&gt;2.2 heap_2&#13;&#10;&lt;/h3&gt;&lt;p&gt;heap_2采用最适应算法，支持释放内存，但是并不能将相临空闲内存块合并，不可避免产生内存碎片。如果需要频繁的创建和删除任务，且所创建的任务堆栈都相同，可以用heap_2&lt;/p&gt;&#10;&lt;p&gt;最适应算法：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;假设heap 有 3 块空闲内存：5,25,50&lt;/li&gt;&#10;&lt;li&gt;申请一个总共20字节的任务，先找到最小能满足的内存：25&lt;/li&gt;&#10;&lt;li&gt;删除任务内存释放后，得到20、5两块内存碎片&lt;/li&gt;&#10;&lt;li&gt;最后存在：5,5,20,50&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;heap_2分配图示：&lt;/p&gt;&#10;&lt;img src="images/image-20250806222759001.png" alt="image-20250806222759001" style="zoom:50%;" /&gt;&#10;&lt;h3 id="23-heap_4"&gt;&lt;a href="#23-heap_4" class="header-anchor"&gt;&lt;/a&gt;2.3 heap_4&#13;&#10;&lt;/h3&gt;&lt;p&gt;heap_4 使用了首次适应算法，能够将空闲且相邻的内存进行合并。适合频繁分配释放大小不同内存。&lt;/p&gt;&#10;&lt;p&gt;首次适应算法：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;假设heap 有 3 块空闲内存（按内存块地址由低到高排序）：5,50,25&lt;/li&gt;&#10;&lt;li&gt;申请一个总共20字节的任务，先找到第一个能满足的内存：50&lt;/li&gt;&#10;&lt;li&gt;删除任务内存释放后，这块内存依旧为50&lt;/li&gt;&#10;&lt;li&gt;最后存在：5,50,25&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;heap_4分配图示：&lt;/p&gt;&#10;&lt;img src="images/image-20250806223412620.png" alt="image-20250806223412620" style="zoom:50%;" /&gt;&#10;&lt;h3 id="24-heap_5"&gt;&lt;a href="#24-heap_5" class="header-anchor"&gt;&lt;/a&gt;2.4 heap_5&#13;&#10;&lt;/h3&gt;&lt;p&gt;heap_5能管理多块不连续内存，但需要用户指定内存区域&lt;/p&gt;&#10;&lt;p&gt;使用如下结构体：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;HeapRegion&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;pucStartAddress&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* 内存区域的起始地址 */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;xSizeInBytes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* 内存区域的大小，单位：字节 */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;HeapRegion_t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;指定多块不连续内存&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;span class="lnt"&gt;7&#10;&lt;/span&gt;&lt;span class="lnt"&gt;8&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Const&lt;/span&gt; &lt;span class="n"&gt;HeapRegion_t&lt;/span&gt; &lt;span class="n"&gt;xHeapRegions&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="mh"&gt;0x80000000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x10000&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="cm"&gt;/* 内存区域1 */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="mh"&gt;0x90000000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xA0000&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="cm"&gt;/* 内存区域2 */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="cm"&gt;/* 数组终止标志 */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;vPortDefineHeapRegions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xHeapRegions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;</description></item></channel></rss>