如何创建个人网站并成功注册一个独特的域名名称?
摘要:个人网站域名名称大全,如何创建网站,怎么做一款网站,江苏工业互联网公司排名目录1.延时函数-介绍2.相对延时函数-解析2.1函数prvAddCurrentTaskToDelayedList-解析2.3滴答定时器中断服务函数xPortSysT
个人网站域名名称大全,如何创建网站,怎么做一款网站,江苏工业互联网公司排名目录1.延时函数-介绍2.相对延时函数-解析2.1函数prvAddCurrentTaskToDelayedList-解析2.3滴答定时器中断服务函数xPortSysTickHandler()-解析2.4函数taskSWITCH_DELAYED_LISTS() -解析3.延时函数-实验4.总结1.延时函数-介绍
函数描述vTaskDelay()相对延时xTaskDelayUntil()绝对…
目录1.延时函数-介绍2.相对延时函数-解析2.1函数prvAddCurrentTaskToDelayedList-解析2.3滴答定时器中断服务函数xPortSysTickHandler()-解析2.4函数taskSWITCH_DELAYED_LISTS() -解析3.延时函数-实验4.总结1.延时函数-介绍
函数描述vTaskDelay()相对延时xTaskDelayUntil()绝对延时相对延时指每次延时都是从执行函数vTaskDelay()开始直到延时指定的时间结束任务被阻塞的时间到调用此函数开始的时间 绝对延时指将整个任务的运行周期看成一个整体适用于需要按照一定频率运行的任务整个任务执行的时间从头到尾的时间。 上图中的xTimeIncrement为绝对延时时间假如绝对延时时间为100ms那么以下三部分之和为100ms包括以下三部分 (1)为任务主体也就是任务真正要做的工作 (2)是任务函数中调用vTaskDelayUntil()对任务进行延时 (3)为其他任务在运行高优先级的任务进行抢占。
2.相对延时函数-解析
首先入口参数必须大于0延时时间有效。
void vTaskDelay( const TickType_t xTicksToDelay ){BaseType_t xAlreadyYielded pdFALSE;/* A delay time of zero just forces a reschedule. */if( xTicksToDelay ( TickType_t ) 0U )vTaskSuspendAll()挂起任务调度器traceTASK_DELAY()函数并没有被实现。 prvAddCurrentTaskToDelayedList点击函数名可跳转至解析 将当前正在执行的任务移到阻塞列表。 vTaskSuspendAll();{traceTASK_DELAY();/* A task that is removed from the event list while the* scheduler is suspended will not get placed in the ready* list or removed from the blocked list until the scheduler* is resumed.** This task cannot be in an event list as it is the currently* executing task. */prvAddCurrentTaskToDelayedList( xTicksToDelay, pdFALSE );}恢复任务调度器。 xAlreadyYielded xTaskResumeAll();判断xAlreadyYielded 是否需要进行任务切换。 else{mtCOVERAGE_TEST_MARKER();}/* Force a reschedule if xTaskResumeAll has not already done so, we may* have put ourselves to sleep. */if( xAlreadyYielded pdFALSE ){portYIELD_WITHIN_API();}else{mtCOVERAGE_TEST_MARKER();}}#endif /* INCLUDE_vTaskDelay */此函数是将任务挂载到阻塞列表解除是在滴答定时器的中断服务函数 xPortSysTickHandler()点击函数名可跳转至解析中。
2.1函数prvAddCurrentTaskToDelayedList-解析
函数prvAddCurrentTaskToDelayedList()有两个入口参数一个是延时时间xTicksToWait另一个是xCanBlockIndefinitely 等于pdFALSE。
static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait,const BaseType_t xCanBlockIndefinitely )xConstTickCount 存储时钟节拍滴答定时器中断一次变量xTickCount加1。宏INCLUDE_xTaskAbortDelay 判断是否是中断延时这里并没有使用所以不用管。
{TickType_t xTimeToWake;const TickType_t xConstTickCount xTickCount;#if ( INCLUDE_xTaskAbortDelay 1 ){/* About to enter a delayed list, so ensure the ucDelayAborted flag is* reset to pdFALSE so it can be detected as having been set to pdTRUE* when the task leaves the Blocked state. */pxCurrentTCB-ucDelayAborted pdFALSE;}#endif将当前正在执行的任务的状态列表项使用函数uxListRemove()从就绪列表中移除移除完判断是否有同等优先级的任务没有就代表只有这一个任务被移除掉后就绪列表中剩余任务为0那么将此优先级的任务优先级复位。 /* Remove the task from the ready list before adding it to the blocked list* as the same list item is used for both lists. */if( uxListRemove( ( pxCurrentTCB-xStateListItem ) ) ( UBaseType_t ) 0 ){/* The current task must be in a ready list, so there is no need to* check, and the port reset macro can be called directly. */portRESET_READY_PRIORITY( pxCurrentTCB-uxPriority, uxTopReadyPriority ); /*lint !e931 pxCurrentTCB cannot change as it is the calling task. pxCurrentTCB-uxPriority and uxTopReadyPriority cannot change as called with scheduler suspended or in a critical section. */}else{mtCOVERAGE_TEST_MARKER();}
宏INCLUDE_vTaskSuspend 判断是否使能挂起判断延时时间xTicksToWait等于最大延时时间并且xCanBlockIndefinitely 不等于pdFALSE此时将任务挂载到挂起列表中由于传入参数为pdFALSE所以不会挂载到挂起列表中则执行else内容。 #if ( INCLUDE_vTaskSuspend 1 ){if( ( xTicksToWait portMAX_DELAY ) ( xCanBlockIndefinitely ! pdFALSE ) ){/* Add the task to the suspended task list instead of a delayed task* list to ensure it is not woken by a timing event. It will block* indefinitely. */listINSERT_END( xSuspendedTaskList, ( pxCurrentTCB-xStateListItem ) );} else中首先记录时间xConstTickCount 为进入函数prvAddCurrentTaskToDelayedList()时记录的时间加上延时时间xTicksToWait就是任务到截止阻塞时间该被恢复的时间通过函数listSET_LIST_ITEM_VALUE将延时时间写入到列表项值里此值将用作挂载到阻塞列表时根据此值进行升序排列 else{/* Calculate the time at which the task should be woken if the event* does not occur. This may overflow but this doesnt matter, the* kernel will manage it correctly. */xTimeToWake xConstTickCount xTicksToWait;/* The list item will be inserted in wake time order. */listSET_LIST_ITEM_VALUE( ( pxCurrentTCB-xStateListItem ), xTimeToWake );判断需要等待截止的时间是否小于进入函数prvAddCurrentTaskToDelayedList()时记录的时间这里判断是否数值溢出如果溢出就将任务挂载到溢出阻塞列表中否则挂载到阻塞列表中。
if( xTimeToWake xConstTickCount ){/* Wake time has overflowed. Place this item in the overflow* list. */vListInsert( pxOverflowDelayedTaskList, ( pxCurrentTCB-xStateListItem ) );}else{/* The wake time has not overflowed, so the current block list* is used. */vListInsert( pxDelayedTaskList, ( pxCurrentTCB-xStateListItem ) );判断下一个阻塞超时时间如果大于新的阻塞时间那么将新的阻塞时间更新为下一个阻塞超时时间。例如下一个xNextTaskUnblockTime 超时时间为30ms新的阻塞时间xTimeToWake为20ms肯定是20ms的先来到所以将下一个阻塞超时时间更新为20ms。 /* If the task entering the blocked state was placed at the* head of the list of blocked tasks then xNextTaskUnblockTime* needs to be updated too. */if( xTimeToWake xNextTaskUnblockTime ){xNextTaskUnblockTime xTimeToWake;}else{mtCOVERAGE_TEST_MARKER();}}}}2.3滴答定时器中断服务函数xPortSysTickHandler()-解析
函数xTaskIncrementTick()的值如果不等于pdFALSE则进行任务切换触发PendSV中断。
void xPortSysTickHandler( void )
{/* The SysTick runs at the lowest interrupt priority, so when this interrupt* executes all interrupts must be unmasked. There is therefore no need to* save and then restore the interrupt mask value as its value is already* known - therefore the slightly faster vPortRaiseBASEPRI() function is used* in place of portSET_INTERRUPT_MASK_FROM_ISR(). */vPortRaiseBASEPRI();{/* Increment the RTOS tick. */if( xTaskIncrementTick() ! pdFALSE ){/* A context switch is required. Context switching is performed in* the PendSV interrupt. Pend the PendSV interrupt. */portNVIC_INT_CTRL_REG portNVIC_PENDSVSET_BIT;}}vPortClearBASEPRIFromISR();
}在函数xTaskIncrementTick()中判断任务是否需要被解除。首先判断任务调度器是否被挂起如果等于pdFALSE 则没有被挂起进入if内容。
BaseType_t xTaskIncrementTick( void )
{TCB_t * pxTCB;TickType_t xItemValue;BaseType_t xSwitchRequired pdFALSE;/* Called by the portable layer each time a tick interrupt occurs.* Increments the tick then checks to see if the new tick value will cause any* tasks to be unblocked. */traceTASK_INCREMENT_TICK( xTickCount );if( uxSchedulerSuspended ( UBaseType_t ) pdFALSE )将系统时钟节拍xTickCount加1然后再将值赋给自己没进来一次时钟节拍将自加1。
/* Minor optimisation. The tick count cannot change in this* block. */const TickType_t xConstTickCount xTickCount ( TickType_t ) 1;/* Increment the RTOS tick, switching the delayed and overflowed* delayed lists if it wraps to 0. */xTickCount xConstTickCount;判断xConstTickCount 是否为0为0则值溢出进入函数 taskSWITCH_DELAYED_LISTS()点击函数名可跳转至解析。
if( xConstTickCount ( TickType_t ) 0U ) /*lint !e774 if does not always evaluate to false as it is looking for an overflow. */{taskSWITCH_DELAYED_LISTS();}else{mtCOVERAGE_TEST_MARKER();}/* See if this tick has made a timeout expire. Tasks are stored in* the queue in the order of their wake time - meaning once one task* has been found whose block time has not expired there is no need to* look any further down the list. */判断当前时钟节拍ConstTickCount 是否大于等于下一个阻塞超时时间。 /* See if this tick has made a timeout expire. Tasks are stored in* the queue in the order of their wake time - meaning once one task* has been found whose block time has not expired there is no need to* look any further down the list. */if( xConstTickCount xNextTaskUnblockTime ){for( ; ; ){判断阻塞列表中是否有任务如果没有任务则没有需要被解除的任务则将下一个阻塞超时时间xNextTaskUnblockTime设置为最大值。 if( listLIST_IS_EMPTY( pxDelayedTaskList ) ! pdFALSE ){/* The delayed list is empty. Set xNextTaskUnblockTime* to the maximum possible value so it is extremely* unlikely that the* if( xTickCount xNextTaskUnblockTime ) test will pass* next time through. */xNextTaskUnblockTime portMAX_DELAY; /*lint !e961 MISRA exception as the casts are only redundant for some ports. */break;}else则阻塞列表中有任务通过函数listGET_OWNER_OF_HEAD_ENTRY()获取阻塞列表的第一个成员的任务控制块通过函数listGET_LIST_ITEM_VALUE()获取列表项的数值列表项中一般存放的是阻塞时间则xItemValue被赋值阻塞时间。 else{/* The delayed list is not empty, get the value of the* item at the head of the delayed list. This is the time* at which the task at the head of the delayed list must* be removed from the Blocked state. */pxTCB listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */xItemValue listGET_LIST_ITEM_VALUE( ( pxTCB-xStateListItem ) );
判断系统时间节拍的数值是否小于阻塞时间代表此时发生异常。因为在首先进入if时判断了当前的系统时钟节拍比下一个阻塞超时时间大。此时将列表项的值赋值给下一个阻塞超时时间退出。
if( xConstTickCount xItemValue ){/* It is not time to unblock this item yet, but the* item value is the time at which the task at the head* of the blocked list must be removed from the Blocked* state - so record the item value in* xNextTaskUnblockTime. */xNextTaskUnblockTime xItemValue;break; /*lint !e9011 Code structure here is deemed easier to understand with multiple breaks. */}else{mtCOVERAGE_TEST_MARKER();}下面的情况为正常执行的情况。使用函数listREMOVE_ITEM()将任务从阻塞列表中移除同时也从使用函数listREMOVE_ITEM从事件列表中移除。 /* It is time to remove the item from the Blocked state. */listREMOVE_ITEM( ( pxTCB-xStateListItem ) );/* Is the task waiting on an event also? If so remove* it from the event list. */if( listLIST_ITEM_CONTAINER( ( pxTCB-xEventListItem ) ) ! NULL ){listREMOVE_ITEM( ( pxTCB-xEventListItem ) );}else{mtCOVERAGE_TEST_MARKER();}
使用函数prvAddTaskToReadyList()将任务添加到就绪列表中 /* Place the unblocked task into the appropriate ready* list. */prvAddTaskToReadyList( pxTCB );判断宏configUSE_PREEMPTION是否使能抢占式任务调度是则判断恢复的任务的任务优先级是否比当前正在执行的任务优先级高是则将任务切换xSwitchRequired变量赋值pdTRUE。 /* A task being unblocked cannot cause an immediate* context switch if preemption is turned off. */#if ( configUSE_PREEMPTION 1 ){/* Preemption is on, but a context switch should* only be performed if the unblocked task has a* priority that is equal to or higher than the* currently executing task. */if( pxTCB-uxPriority pxCurrentTCB-uxPriority ){xSwitchRequired pdTRUE;}else{mtCOVERAGE_TEST_MARKER();}}#endif /* configUSE_PREEMPTION */}}}以下程序是时间片调度 /* Tasks of equal priority to the currently running task will share* processing time (time slice) if preemption is on, and the application* writer has not explicitly turned time slicing off. */#if ( ( configUSE_PREEMPTION 1 ) ( configUSE_TIME_SLICING 1 ) ){if( listCURRENT_LIST_LENGTH( ( pxReadyTasksLists[ pxCurrentTCB-uxPriority ] ) ) ( UBaseType_t ) 1 ){xSwitchRequired pdTRUE;}else{mtCOVERAGE_TEST_MARKER();}}#endif /* ( ( configUSE_PREEMPTION 1 ) ( configUSE_TIME_SLICING 1 ) ) */#if ( configUSE_TICK_HOOK 1 ){/* Guard against the tick hook being called when the pended tick* count is being unwound (when the scheduler is being unlocked). */if( xPendedTicks ( TickType_t ) 0 ){vApplicationTickHook();}else{mtCOVERAGE_TEST_MARKER();}}#endif /* configUSE_TICK_HOOK */#if ( configUSE_PREEMPTION 1 ){if( xYieldPending ! pdFALSE ){xSwitchRequired pdTRUE;}else{mtCOVERAGE_TEST_MARKER();}}#endif /* configUSE_PREEMPTION */}else{xPendedTicks;/* The tick hook gets called at regular intervals, even if the* scheduler is locked. */#if ( configUSE_TICK_HOOK 1 ){vApplicationTickHook();}#endif}return xSwitchRequired;
}2.4函数taskSWITCH_DELAYED_LISTS() -解析
只溢出之后将就绪列表pxDelayedTaskList和溢出就绪列表pxOverflowDelayedTaskList进行互换。
/* pxDelayedTaskList and pxOverflowDelayedTaskList are switched when the tick* count overflows. */
#define taskSWITCH_DELAYED_LISTS() \{ \List_t * pxTemp; \\/* The delayed tasks list should be empty when the lists are switched. */ \configASSERT( ( listLIST_IS_EMPTY( pxDelayedTaskList ) ) ); \\pxTemp pxDelayedTaskList; \pxDelayedTaskList pxOverflowDelayedTaskList; \pxOverflowDelayedTaskList pxTemp; \xNumOfOverflows; \prvResetNextTaskUnblockTime(); \}
3.延时函数-实验 1、实验目的学习 FreeRTOS 相对延时和绝对延时API 函数的使用并了解其区别 2、实验设计将设计三个任务start_task、task1task2 三个任务的功能如下 start_task用来创建task1和task2任务 task1用于展示相对延时函数vTaskDelay ( )的使用 task1用于展示相对延时函数vTaskDelay ( )的使用 task2用于展示绝对延时函数vTaskDelayUntil( )的使用 。 为了直观显示两个延时函数的区别将使用LED0(PB1) 和LED1(PB0) 的翻转波形来表示 1.首先删除无关的程序内容task1和task2程序如下其他程序保持不变。
/* 任务1用于展示相对延时函数vTaskDelay ( )的使用 */
void task1( void * pvParameters )
{while(1){LED0~LED0;vTaskDelay(500);}
}
/* 任务2用于展示绝对延时函数vTaskDelayUntil( )的使用 */
void task2( void * pvParameters )
{while(1){vTaskDelay(10);}
}2.task1中的本身就是使用的相对于延时相对于调用的时候起到延时时间结束所以不用改变task2在使用绝对延时函数vTaskDelayUntil()时可以查看FreeRTOS官网对该函数的使用介绍根据示例来编写函数使用绝对延时是整个task2运行的时间。 由于LED翻转语句执行较快基本看不到差距所以这里加了死延时。
/* 任务1用于展示相对延时函数vTaskDelay ( )的使用 */
void task1( void * pvParameters )
{while(1){LED0~LED0;delay_ms(20);vTaskDelay(500);}
}
/* 任务2用于展示绝对延时函数vTaskDelayUntil( )的使用 */
void task2( void * pvParameters )
{TickType_t xLastWakeTime;xLastWakeTime xTaskGetTickCount(); /* 获取当前的系统时钟节拍 */while(1) {LED1~LED1;delay_ms(20);vTaskDelayUntil(xLastWakeTime,500);}
}这里由于手头没有示波器我并没有做出实验结果理论结果如下。 理论实验结果 由于task1和task2都加了死延时20msLED0翻转周期为520ms左右而LED1的翻转周期仍为500ms。由于task2优先级比task1要高task2会抢占task1所以在执行时会出现task1处于阻塞延时时结束时task2处于死延时此时并不能进行任务切换task1会等到task2死延时结束进入阻塞延时再运行LED0的亮灭时间会有所变化LED0亮灭时间会变长LED1的亮灭周期为500ms保持不变。将task1的优先级变高将会影响task2的绝对延时时间。 4.总结
