FreeRTOS實(shí)時(shí)操作系統(tǒng)空閑任務(wù)的阻塞延時(shí)實(shí)現(xiàn)
什么是阻塞延時(shí)、為什么需要空閑任務(wù)
RTOS中的延時(shí)叫阻塞延時(shí),即任務(wù)需要延時(shí)時(shí),任務(wù)會(huì)放棄cpu使用權(quán),cpu轉(zhuǎn)而去做其他的事,當(dāng)任務(wù)延時(shí)時(shí)間到后,任務(wù)重新請(qǐng)求獲得cpu使用權(quán)。
但當(dāng)所有的任務(wù)都處于阻塞后,為了不讓cpu空閑沒事干就需要一個(gè)空閑任務(wù)讓cpu干活。
空閑任務(wù)的實(shí)現(xiàn)
空閑任務(wù)實(shí)現(xiàn)和創(chuàng)建普通任務(wù)沒區(qū)別,空閑任務(wù)在調(diào)用vTaskStartScheduler函數(shù)內(nèi)部創(chuàng)建,如下
//定義空閑棧
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 128 )
StackType_t IdleTaskStack[configMINIMAL_STACK_SIZE];
//空閑任務(wù)任務(wù)控制塊
TCB_t IdleTaskTCB;
//設(shè)置空閑任務(wù)的參數(shù)
void vApplicationGetIdleTaskMemory( TCB_t **ppxIdleTaskTCBBuffer,
StackType_t **ppxIdleTaskStackBuffer,
uint32_t *pulIdleTaskStackSize )
{
*ppxIdleTaskTCBBuffer=&IdleTaskTCB;
*ppxIdleTaskStackBuffer=IdleTaskStack;
*pulIdleTaskStackSize=configMINIMAL_STACK_SIZE;
}
void vTaskStartScheduler(void)
{
TCB_t *pxIdleTaskTCBBuffer = NULL;//空閑任務(wù)控制塊指針
StackType_t *pxIdleTaskStackBuffer = NULL;//空閑任務(wù)棧指針
uint32_t ulIdleTaskStackSize; //空閑任務(wù)棧大小
//設(shè)置空閑任務(wù)參數(shù)
vApplicationGetIdleTaskMemory(&pxIdleTaskTCBBuffer,
&pxIdleTaskStackBuffer,
&ulIdleTaskStackSize);
//創(chuàng)建空閑任務(wù)
xIdleTaskHandle = xTaskCreateStatic((TaskFunction_t)prvIdleTask,
(char *)"IDLE",
(uint32_t)ulIdleTaskStackSize,
(void*)NULL,
(StackType_t*)pxIdleTaskStackBuffer,
(TCB_t*)pxIdleTaskTCBBuffer);
//將空閑任務(wù)添加到就緒列表
vListInsertEnd(&(pxReadyTasksLists[0]),&(((TCB_t *)pxIdleTaskTCBBuffer)->xStateListItem));
//手動(dòng)指定第一個(gè)要運(yùn)行的任務(wù)
pxCurrentTCB = &Task1TCB;
//啟動(dòng)調(diào)度器
if(xPortStartScheduler()!=pdFALSE)
{
//啟動(dòng)成功則不會(huì)運(yùn)行到這里
}
}
阻塞延時(shí)的實(shí)現(xiàn)
阻塞延時(shí)需要用xTicksToDelay,這個(gè)時(shí)TCB中的一個(gè)成員,用于記錄還要阻塞多久。
typedef struct tskTaskControlBlock
{
volatile StackType_t * pxTopOfStack;
ListItem_t xStateListItem;
StackType_t * pxStack; ·
char pcTaskName[configMAX_TASK_NAME_LEN];
TickType_t xTicksToDelay; //用于延時(shí)
}tskTCB;
所以阻塞延時(shí)就是這樣實(shí)現(xiàn)
void vTaskDelay(const TickType_t xTicksToDelay)
{
TCB_t *pxTCB = NULL;
pxTCB = pxCurrentTCB;
//設(shè)置延時(shí)時(shí)間
pxTCB->xTicksToDelay = xTicksToDelay;
//進(jìn)行一次任務(wù)切換
taskYIELD();
}
由于引入了阻塞延時(shí),所以任務(wù)切換函數(shù)需要改寫,因?yàn)楫?dāng)所有任務(wù)阻塞后,需要切換至空閑任務(wù)運(yùn)行
void vTaskSwitchContext( void )
{ //如果當(dāng)前時(shí)空閑任務(wù),嘗試去執(zhí)行任務(wù)1或任務(wù)2,如果他們延時(shí)時(shí)間都沒到則繼續(xù)執(zhí)行空閑任務(wù)
if( pxCurrentTCB == &IdleTaskTCB )
{
if(Task1TCB.xTicksToDelay == 0)
{
pxCurrentTCB =&Task1TCB;
}
else if(Task2TCB.xTicksToDelay == 0)
{
pxCurrentTCB =&Task2TCB;
}
else
{
return;
}
}
else //當(dāng)前任務(wù)不是空閑任務(wù)會(huì)執(zhí)行到這里
{ //當(dāng)前任務(wù)時(shí)任務(wù)1或任務(wù)2的話,檢查另一個(gè)任務(wù)
//如果另外的任務(wù)不在延時(shí)中,會(huì)切換到該任務(wù)
//否則,判斷當(dāng)前任務(wù)是否在延時(shí)中,是則切換到空閑任務(wù),
//否則,不進(jìn)行任何切換
if (pxCurrentTCB == &Task1TCB)
{
if (Task2TCB.xTicksToDelay == 0)
{
pxCurrentTCB =&Task2TCB;
}
else if (pxCurrentTCB->xTicksToDelay != 0)
{
pxCurrentTCB = &IdleTaskTCB;
}
else
{
return;
}
}
else if (pxCurrentTCB == &Task2TCB)
{
if (Task1TCB.xTicksToDelay == 0)
{
pxCurrentTCB =&Task1TCB;
}
else if (pxCurrentTCB->xTicksToDelay != 0)
{
pxCurrentTCB = &IdleTaskTCB;
}
else
{
return;
}
}
}
}
xTicksToDelay 遞減
vTaskDelay中設(shè)置了xTicksToDelay成員后,是通過SystTick中斷來實(shí)現(xiàn)遞減操作的
void xPortSysTickHandler( void )
{
int x = portSET_INTERRUPT_MASK_FROM_ISR();
xTaskIncrementTick();
portCLEAR_INTERRUPT_MASK_FROM_ISR(x);
}
void xTaskIncrementTick( void )
{
TCB_t *pxTCB = NULL;
BaseType_t i = 0;
const TickType_t xConstTickCount = xTickCount + 1;
xTickCount = xConstTickCount;
for (i=0; i<configMAX_PRIORITIES; i++)
{
pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &pxReadyTasksLists[i] ) );
if (pxTCB->xTicksToDelay > 0)
{
pxTCB->xTicksToDelay --; //這里遞減
}
}
portYIELD();
}
SysTick初始化
//systick控制寄存器
#define portNVIC_SYSTICK_CTRL_REG (*((volatile uint32_t *) 0xe000e010 ))
//systick重裝載寄存器
#define portNVIC_SYSTICK_LOAD_REG (*((volatile uint32_t *) 0xe000e014 ))
//systick時(shí)鐘源選擇
#ifndef configSYSTICK_CLOCK_HZ
#define configSYSTICK_CLOCK_HZ configCPU_CLOCK_HZ
#define portNVIC_SYSTICK_CLK_BIT ( 1UL << 2UL )
#else
#define portNVIC_SYSTICK_CLK_BIT ( 0 )
#endif
#define portNVIC_SYSTICK_INT_BIT ( 1UL << 1UL )
#define portNVIC_SYSTICK_ENABLE_BIT ( 1UL << 0UL )
void vPortSetupTimerInterrupt( void )
{
//重裝載計(jì)數(shù)器值
portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
//設(shè)置systick時(shí)鐘使用內(nèi)核時(shí)鐘
//使能systick定時(shí)器中斷
//使能systick定時(shí)器
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT |
portNVIC_SYSTICK_INT_BIT |
portNVIC_SYSTICK_ENABLE_BIT );
}
在FreeRTOSConfig.h中
#define configCPU_CLOCK_HZ (( unsigned long ) 25000000) #define configTICK_RATE_HZ (( TickType_t ) 100)
configSYSTICK_CLOCK_HZ是沒有定義的,所以configSYSTICK_CLOCK_HZ使用的是configCPU_CLOCK_HZ
仿真
portCHAR flag1;
portCHAR flag2;
TaskHandle_t Task1_Handle;
StackType_t Task1Stack[128];
TCB_t Task1TCB;
TaskHandle_t Task2_Handle;
StackType_t Task2Stack[128];
TCB_t Task2TCB;
void Task1_Fntry(void *arg)
{
while(1)
{
flag1=1;
vTaskDelay( 2 );
flag1=0;
vTaskDelay( 2 );
}
}
void Task2_Fntry(void *arg)
{
while(1)
{
flag2=1;
vTaskDelay( 2 );
flag2=0;
vTaskDelay( 2 );
}
}
int main(void)
{
prvInitialiseTaskLists();
Task1_Handle = xTaskCreateStatic(Task1_Fntry,"task1",128,NULL,Task1Stack,&Task1TCB);
vListInsertEnd(&pxReadyTasksLists[1],&((&Task1TCB)->xStateListItem));
Task2_Handle = xTaskCreateStatic(Task2_Fntry,"task2",128,NULL,Task2Stack,&Task2TCB);
vListInsertEnd(&pxReadyTasksLists[2],&((&Task2TCB)->xStateListItem));
vTaskStartScheduler();
for(;;)
{}
}
可以看到2個(gè)task是同步運(yùn)行的,且延時(shí)是20ms

以上就是FreeRTOS實(shí)時(shí)操作系統(tǒng)空閑任務(wù)的阻塞延時(shí)實(shí)現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于FreeRTOS空閑任務(wù)阻塞延時(shí)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- FreeRTOS實(shí)時(shí)操作系統(tǒng)的任務(wù)創(chuàng)建與任務(wù)切換
- FreeRTOS實(shí)時(shí)操作系統(tǒng)的任務(wù)創(chuàng)建和刪除
- FreeRTOS進(jìn)階之任務(wù)通知示例完全解析
- FreeRTOS使用任務(wù)通知實(shí)現(xiàn)命令行解釋器
- FreeRTOS實(shí)時(shí)操作系統(tǒng)的任務(wù)通知方法
- FreeRTOS實(shí)時(shí)操作系統(tǒng)的任務(wù)應(yīng)用函數(shù)詳解
- FreeRTOS任務(wù)控制API函數(shù)的功能分析
- FreeRTOS進(jìn)階之任務(wù)創(chuàng)建完全解析
相關(guān)文章
FreeRTOS實(shí)時(shí)操作系統(tǒng)之可視化追蹤調(diào)試
這篇文章主要為大家介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)之可視化追蹤調(diào)試的示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04
FreeRTOS動(dòng)態(tài)內(nèi)存分配管理heap_5示例
這篇文章主要為大家介紹了FreeRTOS動(dòng)態(tài)內(nèi)存分配管理heap_5示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04
FreeRTOS實(shí)時(shí)操作系統(tǒng)臨界段保護(hù)場(chǎng)合示例
這篇文章主要為大家介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)臨界段保護(hù)場(chǎng)合示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04
FreeRTOS實(shí)時(shí)操作系統(tǒng)多任務(wù)管理基礎(chǔ)知識(shí)
這篇文章主要為大家介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)多任務(wù)管理的基礎(chǔ)知識(shí),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04
FreeRTOS進(jìn)階之任務(wù)通知示例完全解析
這篇文章主要為大家介紹了FreeRTOS進(jìn)階系列之任務(wù)通知的示例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04
FreeRTOS進(jìn)階之任務(wù)創(chuàng)建完全解析
這篇文章主要為大家介紹了FreeRTOS進(jìn)階之任務(wù)創(chuàng)建完全解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04
freertos實(shí)時(shí)操作系統(tǒng)臨界段保護(hù)開關(guān)中斷及進(jìn)入退出
這篇文章主要介紹了freertos實(shí)時(shí)操作系統(tǒng)臨界段保護(hù)開關(guān)中斷及進(jìn)入退出,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04
FreeRTOS編碼標(biāo)準(zhǔn)及風(fēng)格指南
這篇文章主要為大家介紹了FreeRTOS編碼標(biāo)準(zhǔn)及風(fēng)格指南,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04
FreeRTOS實(shí)時(shí)操作系統(tǒng)空閑任務(wù)的阻塞延時(shí)實(shí)現(xiàn)
這篇文章主要為大家介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)空閑任務(wù)的阻塞延時(shí)實(shí)現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04
FreeRTOS軟件定時(shí)器apollo中斷狀態(tài)判斷
這篇文章主要為大家介紹了FreeRTOS軟件定時(shí)器apollo中斷狀態(tài)的判斷,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04

