任务调度机制
分给每个任务一个时间片osdelay()阻塞;
ISR CPU物理中断(优先级最高)
任务特性
每创建都是一个main
RAM和ROM有限内没有限制
FREEROTS中序号越高优先级越高
μCOS序号越低越高
堆栈:TASK(){while(1){}}
函数在堆里占用寄存器
R0-R15 PSR
任务状态
就绪:将运行时告诉操作系统:准备好等待调度
释放机制:挂起态和调度器说拜拜
:阻塞态osdelay(500)延时一到进入就绪状态
任务优先级
空闲任务:OS运行条件有且一个任务,启动操作系统
前两个必须是阻塞程序阻塞态
while循环和for区别
while会转汇编时多一个判断,for就是直接循环处理效率最高
保存CPU环境任务堆栈信息
嵌套函数在栈里
MSP裸机 PSP
提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
提示:以下是本篇文章正文内容,下面案例可供参考
功能需求
1、创建任务
2、在任务中1S钟打印(串口输出)一次任务运行标志
任务创建API
xTaskCreate()动态创建
xTaskCreateStatic()静态创建
功能实现
uart1选择异步通讯方式
FROTS选择
内存分配方式动态与静态同时使用
task新建一个任务重命名和函数名
优先级选low
Alliocation选择静态分配
FREEROTS 代码如下:
void USART_TASK(void *argument)
{
/* USER CODE BEGIN USART_TASK */
/* Infinite loop */
for(;;)
{
printf("USARTTASK\n");
osDelay(1);
}
/* USER CODE END USART_TASK */
}
mian代码如下:
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Init scheduler */
osKernelInitialize(); /* Call init function for freertos objects (in freertos.c) */
MX_FREERTOS_Init();
/* Start scheduler */
osKernelStart();
/* We should never get here as control is now taken by the scheduler */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
功能需求
1、创建按键检测任务
2、当按键按下时,挂起LED闪烁任务
3、当按键松开时,恢复LED闪烁任务
按键初始化配置为上升沿和下降沿触发,开启中断,FREEROTS新建任务,优先级选择高一点normal,动态分配
freertos.c代码如下:
/* USER CODE BEGIN Header */
/**
******************************************************************************
* File Name : freertos.c
* Description : Code for freertos applications
******************************************************************************
* @attention
*
* © Copyright (c) 2021 STMicroelectronics.
* All rights reserved.
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "gpio.h"
extern tekeystatus keystatus;
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
typedef StaticTask_t osStaticThreadDef_t;
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */
/* USER CODE END Variables */
/* Definitions for LedTask */
osThreadId_t LedTaskHandle;
const osThreadAttr_t LedTask_attributes = {
.name = "LedTask",
.priority = (osPriority_t) osPriorityNormal,
.stack_size = 128 * 4
};
/* Definitions for USARTTASK */
osThreadId_t USARTTASKHandle;
uint32_t USARTTASKBuffer[ 128 ];
osStaticThreadDef_t USARTTASKControlBlock;
const osThreadAttr_t USARTTASK_attributes = {
.name = "USARTTASK",
.stack_mem = &USARTTASKBuffer[0],
.stack_size = sizeof(USARTTASKBuffer),
.cb_mem = &USARTTASKControlBlock,
.cb_size = sizeof(USARTTASKControlBlock),
.priority = (osPriority_t) osPriorityLow,
};
/* Definitions for keytask */
osThreadId_t keytaskHandle;
const osThreadAttr_t keytask_attributes = {
.name = "keytask",
.priority = (osPriority_t) osPriorityBelowNormal,
.stack_size = 128 * 4
};
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */
/* USER CODE END FunctionPrototypes */
void Led_Task(void *argument);
void USART_TASK(void *argument);
void key_task(void *argument);
void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */
/**
* @brief FreeRTOS initialization
* @param None
* @retval None
*/
void MX_FREERTOS_Init(void) {
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* USER CODE BEGIN RTOS_MUTEX */
/* add mutexes, ... */
/* USER CODE END RTOS_MUTEX */
/* USER CODE BEGIN RTOS_SEMAPHORES */
/* add semaphores, ... */
/* USER CODE END RTOS_SEMAPHORES */
/* USER CODE BEGIN RTOS_TIMERS */
/* start timers, add new ones, ... */
/* USER CODE END RTOS_TIMERS */
/* USER CODE BEGIN RTOS_QUEUES */
/* add queues, ... */
/* USER CODE END RTOS_QUEUES */
/* Create the thread(s) */
/* creation of LedTask */
LedTaskHandle = osThreadNew(Led_Task, NULL, &LedTask_attributes);
/* creation of USARTTASK */
USARTTASKHandle = osThreadNew(USART_TASK, NULL, &USARTTASK_attributes);
/* creation of keytask */
keytaskHandle = osThreadNew(key_task, NULL, &keytask_attributes);
/* USER CODE BEGIN RTOS_THREADS */
/* add threads, ... */
/* USER CODE END RTOS_THREADS */
/* USER CODE BEGIN RTOS_EVENTS */
/* add events, ... */
/* USER CODE END RTOS_EVENTS */
}
/* USER CODE BEGIN Header_Led_Task */
/**
* @brief Function implementing the LedTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_Led_Task */
void Led_Task(void *argument)
{
/* USER CODE BEGIN Led_Task */
/* Infinite loop */
for(;;)
{
//GPIOF->BSRR=(1<<23);//点亮 库函数版HAL_GPIO_WritePin(GPIOF,GPIO_PIN_7,GPIO_PIN_RESET);
//GPIOF->BSRR=(1<<7);//熄灭 库函数版HAL_GPIO_WritePin(GPIOF,GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10,GPIO_PIN_SET);
HAL_GPIO_WritePin(Led6_GPIO_Port, Led6_Pin, GPIO_PIN_RESET);
osDelay(500);//1ms时基
HAL_GPIO_WritePin(Led6_GPIO_Port, Led6_Pin, GPIO_PIN_SET);
osDelay(500);//1ms时基
}
/* USER CODE END Led_Task */
}
/* USER CODE BEGIN Header_USART_TASK */
/**
* @brief Function implementing the USARTTASK thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_USART_TASK */
void USART_TASK(void *argument)
{
/* USER CODE BEGIN USART_TASK */
/* Infinite loop */
for(;;)
{
printf("USARTTASK\n");
osDelay(1);
}
/* USER CODE END USART_TASK */
}
/* USER CODE BEGIN Header_key_task */
/**
* @brief Function implementing the keytask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_key_task */
void key_task(void *argument)
{
/* USER CODE BEGIN key_task */
keystatus=KEYRESET;
/* Infinite loop */
for(;;)
{
if(keystatus==KEYDOWN)
{
//挂起
vTaskSuspend(keytaskHandle);
keystatus=KEYRESET;
}
if(keystatus==KEYUP)
{
//恢复
vTaskResume(keytaskHandle);
keystatus=KEYRESET;
}
osDelay(10);
}
/* USER CODE END key_task */
}
/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */
/* USER CODE END Application */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
gpio.c代码如下:
/**
******************************************************************************
* @file gpio.c
* @brief This file provides code for the configuration
* of all used GPIO pins.
******************************************************************************
* @attention
*
* © Copyright (c) 2021 STMicroelectronics.
* All rights reserved.
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "gpio.h"
/* USER CODE BEGIN 0 */
#include "stdio.h"
tekeystatus keystatus;
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(key3_Pin==GPIO_Pin)
{
if(HAL_GPIO_ReadPin(key3_GPIO_Port,key3_Pin)==GPIO_PIN_SET)
{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(key3_GPIO_Port,key3_Pin)==GPIO_PIN_SET)
{
printf("KEY up\n");
keystatus=KEYUP;
}
else{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(key3_GPIO_Port,key3_Pin)==GPIO_PIN_RESET)
{
printf("KEY down\n");
keystatus=KEYDOWN;
}
}
}
}
}
/* USER CODE END 0 */
/*----------------------------------------------------------------------------*/
/* Configure GPIO */
/*----------------------------------------------------------------------------*/
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOI_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(Led6_GPIO_Port, Led6_Pin, GPIO_PIN_SET);
/*Configure GPIO pin : PtPin */
GPIO_InitStruct.Pin = key3_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(key3_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : PtPin */
GPIO_InitStruct.Pin = Led6_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(Led6_GPIO_Port, &GPIO_InitStruct);
/* EXTI interrupt init*/
HAL_NVIC_SetPriority(EXTI9_5_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
}
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
gpio.h代码如下:
/**
******************************************************************************
* @file gpio.h
* @brief This file contains all the function prototypes for
* the gpio.c file
******************************************************************************
* @attention
*
* © Copyright (c) 2021 STMicroelectronics.
* All rights reserved.
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __GPIO_H__
#define __GPIO_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* USER CODE BEGIN Includes */
typedef enum
{
KEYUP,
KEYDOWN,
KEYRESET,
}tekeystatus;
/* USER CODE END Includes */
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
void MX_GPIO_Init(void);
/* USER CODE BEGIN Prototypes */
/* USER CODE END Prototypes */
#ifdef __cplusplus
}
#endif
#endif /*__ GPIO_H__ */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
FreeRTOS的每个任务都有一些属性需要存储
把这些属性集合到一起用一个结构体表示
这个结构体叫做任务控制块(TCB_t)
静态动态都要分配一个空间RAM(地址)
栈先入后出,起始地址结束地址防止溢出
状态链表
*pxTopOfStack | 任务堆栈栈顶 |
---|---|
xStateListItem | 状态列表项 |
xEventListItem | 事件列表项 |
uxPriority | 任务优先级 |
*pxStack | 任务栈起始地址 |
uxPrioritypcTaskName[] | 任务名称 |
uxPriority*pxEndOfStack | 任务堆栈栈底 |
typedef struct tskTaskControlBlock
{
//任务栈顶
volatile StackType_t *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */
//状态列表、事件列表
ListItem_t xStateListItem; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */
ListItem_t xEventListItem; /*< Used to reference a task from an event list. */
//任务优先级
UBaseType_t uxPriority; /*< The priority of the task. 0 is the lowest priority. */
//任务栈地址
StackType_t *pxStack; /*< Points to the start of the stack. */
//任务名称
char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
} tskTCB;
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
const char * const pcName,
const uint16_t usStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
{
TCB_t *pxNewTCB;
BaseType_t xReturn;
/* 根据你使用的硬件平台的区别*/
这个区别是什么呢?
指的 硬件平台栈增长方式
我们选择M4,分析M4的栈增长方式就可以
在M4的权威指南里 4.4.3-栈存储分析
#define portSTACK_GROWTH ( -1 ) 表示满减栈
*/
#if( portSTACK_GROWTH > 0 )
{
}
#else /* portSTACK_GROWTH */
{
StackType_t *pxStack;
/* 任务栈内存分配*/
pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
if( pxStack != NULL )
{
/* 任务控制块内存分配 */
pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); /*lint !e961 MISRA exception as the casts are only redundant for some paths. */
if( pxNewTCB != NULL )
{
/* 赋值栈地址 */
pxNewTCB->pxStack = pxStack;
}
else
{
/* 释放栈空间 */
vPortFree( pxStack );
}
}
else
{
//没有分配成功
pxNewTCB = NULL;
}
}
#endif /* portSTACK_GROWTH */
if( pxNewTCB != NULL )
{
//新建任务初始化
prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL );
//把任务添加到就绪列表中
prvAddNewTaskToReadyList( pxNewTCB );
xReturn = pdPASS;
}
else
{
xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
}
return xReturn;
}
static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
const char * const pcName,
const uint32_t ulStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask,
TCB_t *pxNewTCB,
const MemoryRegion_t * const xRegions ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
{
StackType_t *pxTopOfStack;
UBaseType_t x;
/* 计算栈顶的地址 */
#if( portSTACK_GROWTH < 0 )
{
//把栈空间的高地址分配给栈顶
pxTopOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 );
//栈对齐---- 栈要8字节对齐
pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) ); /*lint !e923 MISRA exception. Avoiding casts between pointers and integers is not practical. Size differences accounted for using portPOINTER_SIZE_TYPE type. */
/* 检查是否有错误 */
configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
}
#else /* portSTACK_GROWTH */
{
}
#endif /* portSTACK_GROWTH */
/* 存储任务名称 */
for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ )
{
pxNewTCB->pcTaskName[ x ] = pcName[ x ];
/* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than
configMAX_TASK_NAME_LEN characters just in case the memory after the
string is not accessible (extremely unlikely). */
if( pcName[ x ] == 0x00 )
{
break;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
/* \0补齐字符串 */
pxNewTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0';
/* 判断任务分配的优先级,是否大于最大值 如果超过最大值,赋值最大值*/
if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
{
uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
//赋值任务优先级到任务控制块
pxNewTCB->uxPriority = uxPriority;
//任务状态表 事件表初始化
vListInitialiseItem( &( pxNewTCB->xStateListItem ) );
vListInitialiseItem( &( pxNewTCB->xEventListItem ) );
/* 任务控制块链接到任务状态表中 */
listSET_LIST_ITEM_OWNER( &( pxNewTCB->xStateListItem ), pxNewTCB );
/* 任务控制块连接到事件表中 */
listSET_LIST_ITEM_VALUE( &( pxNewTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
listSET_LIST_ITEM_OWNER( &( pxNewTCB->xEventListItem ), pxNewTCB );
/* Initialize the TCB stack to look as if the task was already running,
but had been interrupted by the scheduler. The return address is set
to the start of the task function. Once the stack has been initialised
the top of stack variable is updated. */
#if( portUSING_MPU_WRAPPERS == 1 )
{
}
#else /* portUSING_MPU_WRAPPERS */
{
//任务堆栈初始化,之后返回任务栈顶
pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
}
#endif /* portUSING_MPU_WRAPPERS */
if( ( void * ) pxCreatedTask != NULL )
{
/* 赋值任务句柄 */
*pxCreatedTask = ( TaskHandle_t ) pxNewTCB;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
//阅读M4权威指南,第八章节,分析异常处理
//为什么分析异常处理----------任务调度其实就是通过CPU内核异常处理实现的
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
{
pxTopOfStack--;
//入栈程序状态寄存器
*pxTopOfStack = portINITIAL_XPSR; /* xPSR */
pxTopOfStack--;
//入栈PC指针
*pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK; /* PC */
pxTopOfStack--;
//入栈LR链接寄存器
*pxTopOfStack = ( StackType_t ) prvTaskExitError; /* LR */
/* 不需要初始化 */
pxTopOfStack -= 5; /* R12, R3, R2 and R1. */
//R0作为传参入栈
*pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
/* 异常返回值入栈 返回值是确定程序使用的栈地址是哪一个 MSP PSP*/
pxTopOfStack--;
*pxTopOfStack = portINITIAL_EXEC_RETURN;
//不初始化
pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */
//最终返回栈顶
return pxTopOfStack;
}
挂起恢复删除代码如下:
/**
void vTaskSuspend( TaskHandle_t xTaskToSuspend )
{
TCB_t *pxTCB;
//进入临街段----后面讲原理
taskENTER_CRITICAL();
{
/* 获取任务控制块 */
pxTCB = prvGetTCBFromHandle( xTaskToSuspend );
/* 从就绪列表中移除 */
if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
{
taskRESET_READY_PRIORITY( pxTCB->uxPriority );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* 从事件列表中移除 */
if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
{
( void ) uxListRemove( &( pxTCB->xEventListItem ) );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
//把任务添加到挂起列表中
vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );
}
//退出临界段
taskEXIT_CRITICAL();
//判断调度器是否开启
if( xSchedulerRunning != pdFALSE )
{
/* 更新下个任务锁定时间-------在删除任务里面已经讲解 */
taskENTER_CRITICAL();
{
prvResetNextTaskUnblockTime();
}
taskEXIT_CRITICAL();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
if( pxTCB == pxCurrentTCB )
{
if( xSchedulerRunning != pdFALSE )
{
/* 直接进行任务调度,释放CPU的使用权 */
configASSERT( uxSchedulerSuspended == 0 );
portYIELD_WITHIN_API();
}
else
{
/* 调度器没有开启,读取当前任务挂起列表的长度
如果说,挂起列表,已经把所有任务挂起
*/
if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks )
{
/* 把当前的任务控制块赋值为NULL
不让任务控制块再使用了
*/
pxCurrentTCB = NULL;
}
else
{
//任务上下文切换------在后面讲
//其实就是在就绪列表中找到优先级最高的任务,进行调度
vTaskSwitchContext();
}
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
void vTaskResume( TaskHandle_t xTaskToResume )
{
//获取要恢复的任务控制块
TCB_t * const pxTCB = ( TCB_t * ) xTaskToResume;
/*检查 */
configASSERT( xTaskToResume );
/*既然要使用任务控制块,肯定不是为NULL
如果任务控制块,是当前的任务,是错误,是不允许
*/
if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) )
{
//进入临街段
taskENTER_CRITICAL();
{
//判断任务是否已经挂起
if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE )
{
/* 从挂起列表中移除 */
( void ) uxListRemove( &( pxTCB->xStateListItem ) );
//添加任务到就绪列表
prvAddTaskToReadyList( pxTCB );
/* 判断要恢复的任务是否大于当前任务的优先级
如果大于,释放CPU的使用权,开始内核调度
前提条件,是已经使能了 抢占式调度器
*/
if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
{
/* */
taskYIELD_IF_USING_PREEMPTION();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
//退出临街段
taskEXIT_CRITICAL();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
void vTaskDelete( TaskHandle_t xTaskToDelete )
{
TCB_t *pxTCB;
//进入临界段
taskENTER_CRITICAL();
{
/* 获取任务控制块 -----参数传入的是任务句柄
判断是任务本身,还是其他任务
如果是当前任务,传入的参数为NULL
*/
pxTCB = prvGetTCBFromHandle( xTaskToDelete );
/* 从就绪列表中移除 */
if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
{
taskRESET_READY_PRIORITY( pxTCB->uxPriority );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* I从事件列表中移除*/
if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
{
( void ) uxListRemove( &( pxTCB->xEventListItem ) );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* */
uxTaskNumber++;
//如果是删除当前任务
if( pxTCB == pxCurrentTCB )
{
/* 不能再此删除,在空闲任务中删除
就把任务添加到等待删除的任务列表中
*/
vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xStateListItem ) );
/* 给空间任务一个标记 */
++uxDeletedTasksWaitingCleanUp;
/* 钩子函数---------需要用户自己实现*/
portPRE_TASK_DELETE_HOOK( pxTCB, &xYieldPending );
}
else
{
//直接删除任务控制块
--uxCurrentNumberOfTasks;
prvDeleteTCB( pxTCB );
/* 复位任务锁定时间 ----------时间片 操作系统会记录一个最新的时间,
根据最新的时间,进行调度,所以删除任务后,要更新锁定时间*/
prvResetNextTaskUnblockTime();
}
traceTASK_DELETE( pxTCB );
}
//退出临界段
taskEXIT_CRITICAL();
/* 判断调度器是否开启 */
if( xSchedulerRunning != pdFALSE )
{
//如果是删除任务本身,马上进行任务调度(释放CPU的使用权)
if( pxTCB == pxCurrentTCB )
{
configASSERT( uxSchedulerSuspended == 0 );
portYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}