FreeRTOS(进阶)

挂起 恢复

相关API

在这里插入图片描述
1、函数 vTaskSuspend()
此函数用于将某个任务设置为挂起态,进入挂起态的任务永远都不会进入运行态。退出挂起态的唯一方法就是调用任务恢复函数 vTaskResume()或 xTaskResumeFromISR()。

2、函数 vTaskResume()
将一个任务从挂起态恢复到就绪态,只有通过函数 vTaskSuspend()设置为挂起态的任务才可以使用 vTaskRexume()恢复!

3、函数 xTaskResumeFromISR()
此函数是 vTaskResume()的中断版本,用于在中断服务函数中恢复一个任务。

挂起恢复

void Key_task( void * pvParameters )
{
		
	  while(1)
		{
				if( GPIO_ReadInputDataBit( GPIOA,  GPIO_Pin_0) == 0)
				{
						vTaskDelay(100);
						vTaskSuspend(Task2Task_Handler);//挂起
						printf("Task1 is Suspend! \r\n");
				}
				/*
				if( GPIO_ReadInputDataBit( GPIOA,  GPIO_Pin_1) == 0)
				{
						vTaskDelay(100);
						vTaskResume(Task2Task_Handler);//恢复
						printf("Task1 is Suspend! \r\n");
				}
				*/

		}
}

外部中断恢复

void EXTI4_IRQHandler(void)
{
		BaseType_t YieldRequired;
		delay_xms(20); //消抖
		if( GPIO_ReadInputDataBit( GPIOA,  GPIO_Pin_2)==0)
		{
				YieldRequired=xTaskResumeFromISR(Task2Task_Handler);//恢复任务 2 (2)
				printf("恢复任务 2 的运行!\r\n");
				if(YieldRequired==pdTRUE)
				{
				/*如果函数 xTaskResumeFromISR()返回值为 pdTRUE,那么说明要恢复的这个
				任务的任务优先级等于或者高于正在运行的任务(被中断打断的任务),所以在
				退出中断的时候一定要进行上下文切换!*/
						portYIELD_FROM_ISR(YieldRequired);
				} 
		}
		EXTI_ClearITPendingBit(EXTI_Line2);//清除 LINE2 上的中断标志位 
}

根据函数 xTaskResumeFromISR()的返回值来确定是否需要进行上下文切换。当返回值为 pdTRUE 的时候就需要调用函数 portYIELD_FROM_ISR()进行上下文切换,否则的话不需要。

中断

开中断函数 portENABLE_INTERRUPTS()
关中断函数 portDISABLE_INTERRUPTS()

两个定时器 一个定时器优先级4 一个定时器优先级5

#include "timer.h"
#include "led.h"
#include "usart.h"	  


//通用定时器3中断初始化
//arr:自动重装值。
//psc:时钟预分频数
//定时器溢出时间计算方法:Tout=((arr+1)*(psc+1))/Ft us.
//Ft=定时器工作频率,单位:Mhz
//这里使用的是定时器3!
void TIM3_Int_Init(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);  ///使能TIM3时钟
	
  TIM_TimeBaseInitStructure.TIM_Period = 10000 -1; 	
	TIM_TimeBaseInitStructure.TIM_Prescaler= 3600 -1;  //定时器分频
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; 
	
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);//初始化TIM3
	
	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); //允许定时器3更新中断
	TIM_Cmd(TIM3,ENABLE); //使能定时器3
	
	NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn; //定时器3中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=4; //抢占优先级4
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0; //子优先级0
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	
}
  
void TIM4_Int_Init(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);  ///使能TIM3时钟
	
  TIM_TimeBaseInitStructure.TIM_Period = 10000 -1; 	
	TIM_TimeBaseInitStructure.TIM_Prescaler= 3600 -1;  //定时器分频
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; 
	
	TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStructure);//初始化TIM3
	
	TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE); //允许定时器3更新中断
	TIM_Cmd(TIM4,ENABLE); //使能定时器3
	
	NVIC_InitStructure.NVIC_IRQChannel=TIM4_IRQn; //定时器3中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=5; //抢占优先级4
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0; //子优先级0
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	
}

//定时器3中断服务函数
void TIM3_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM3,TIM_IT_Update)!=RESET) //溢出中断
	{
			printf("Tim3 is interrupt! \r\n");
	}
	TIM_ClearITPendingBit(TIM3,TIM_IT_Update);  //清除中断标志位
}

void TIM4_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM4,TIM_IT_Update)!=RESET) //溢出中断
	{
			printf("Tim4 is interrupt! \r\n");
	}
	TIM_ClearITPendingBit(TIM4,TIM_IT_Update);  //清除中断标志位
}

中断测试任务函数

void INTERRUPT_task( void * pvParameters )
{
		char Task_num = 0;
		while(1)
		{
				Task_num ++;
				if(Task_num == 5)
				{
						printf("关闭中断 \r\n");
						portDISABLE_INTERRUPTS();
						delay_xms(5000);
						printf("开启中断 \r\n");
						portENABLE_INTERRUPTS();
				}
				LED0 = ~LED0;
				vTaskDelay(1000);
		}
}
	

列表与列表项

列表和列表项是FreeRTOS的一个数据结构,FreeRTOS 大量使用到了列表和列表项,它是 FreeRTOS 的基石。

插入值为 40 的列表项
在这里插入图片描述

再插入值为 60 的列表项
在这里插入图片描述

列表项末尾插入50

在这里插入图片描述

初始化列表

void vListInitialise( List_t * const pxList )

初始化列表项

void vListInitialiseItem( ListItem_t * const pxItem )

定义列表与列表项

List_t TestList;
ListItem_t ListItem1;
ListItem_t ListItem2;
ListItem_t ListItem3;

初始化值并打印

		ListItem1.xItemValue = 40;
		ListItem2.xItemValue = 60;
		ListItem3.xItemValue = 50;
		printf("---------列表与列表项地址-------- \r\n");
		printf("项目                  地址        \r\n");
		printf("TestList              %#x         \r\n",(int)&TestList);
		printf("TestList->pxIndex     %#x         \r\n",(int)TestList.pxIndex);
		printf("TestList->xListEnd    %#x         \r\n",(int)&TestList.xListEnd);
		printf("ListItem1     %#x                 \r\n",(int)&(ListItem1));
		printf("ListItem2     %#x                 \r\n",(int)&(ListItem2));
		printf("ListItem3     %#x                 \r\n",(int)&(ListItem3));

插入列表项

void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )

// 插入列表项ListItem1
		vListInsert(&TestList,&ListItem1);
		printf("-----------------添加列表项ListTtem1--------------- \r\n");
		printf("项目                                    地址        \r\n");
		printf("TestList->xlistEnd->pxNext              %#x         \r\n",(int)(TestList.xListEnd.pxNext));
		printf("ListItem1->pxNext                       %#x         \r\n",(int)(ListItem1.pxNext));
		printf("------------------前后连接分割线-------------------- \r\n");
		printf("TestList->xListEnd.pxPrevious           %#x         \r\n",(int)(TestList.xListEnd.pxPrevious));
		printf("ListItem1->pxPrevious                   %#x         \r\n",(int)(ListItem1.pxPrevious));
		
		
		printf("-------------------------结束---------------------- \r\n");
// 插入列表项ListItem2
		vListInsert(&TestList,&ListItem2);
		printf("-----------------添加列表项ListTtem2--------------- \r\n");
		printf("项目                                    地址        \r\n");
		printf("TestList->xlistEnd->pxNext              %#x         \r\n",(int)(TestList.xListEnd.pxNext));
		printf("ListItem1->pxNext                       %#x         \r\n",(int)(ListItem1.pxNext));
		printf("ListItem2->pxNext                       %#x         \r\n",(int)(ListItem2.pxNext));
		
		printf("------------------前后连接分割线-------------------- \r\n");
		printf("TestList->xListEnd.pxPrevious           %#x         \r\n",(int)(TestList.xListEnd.pxPrevious));
		printf("ListItem1->pxPrevious                   %#x         \r\n",(int)(ListItem1.pxPrevious));
		printf("ListItem2->pxPrevious                   %#x         \r\n",(int)(ListItem2.pxPrevious));		
		
		printf("-------------------------结束---------------------- \r\n");
// 插入列表项ListItem3
		vListInsert(&TestList,&ListItem3);
		printf("-----------------添加列表项ListTtem3--------------- \r\n");
		printf("项目                                    地址        \r\n");
		printf("TestList->xlistEnd->pxNext              %#x         \r\n",(int)(TestList.xListEnd.pxNext));
		printf("ListItem1->pxNext                       %#x         \r\n",(int)(ListItem1.pxNext));
		printf("ListItem2->pxNext                       %#x         \r\n",(int)(ListItem2.pxNext));
		printf("ListItem3->pxNext                       %#x         \r\n",(int)(ListItem3.pxNext));
	
		printf("------------------前后连接分割线-------------------- \r\n");
		printf("TestList->xListEnd.pxPrevious           %#x         \r\n",(int)(TestList.xListEnd.pxPrevious));
		printf("ListItem1->pxPrevious                   %#x         \r\n",(int)(ListItem1.pxPrevious));
		printf("ListItem2->pxPrevious                   %#x         \r\n",(int)(ListItem2.pxPrevious));		
		printf("ListItem3->pxPrevious                   %#x         \r\n",(int)(ListItem3.pxPrevious));		
		
		printf("-------------------------结束---------------------- \r\n");

删除列表项

UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )

		uxListRemove(&ListItem2);
		printf("-----------------删除列表项ListTtem3--------------- \r\n");
		printf("项目                                    地址        \r\n");
		printf("TestList->xlistEnd->pxNext              %#x         \r\n",(int)(TestList.xListEnd.pxNext));
		printf("ListItem1->pxNext                       %#x         \r\n",(int)(ListItem1.pxNext));
		printf("ListItem3->pxNext                       %#x         \r\n",(int)(ListItem3.pxNext));
	
		printf("------------------前后连接分割线-------------------- \r\n");
		printf("TestList->xListEnd.pxPrevious           %#x         \r\n",(int)(TestList.xListEnd.pxPrevious));
		printf("ListItem1->pxPrevious                   %#x         \r\n",(int)(ListItem1.pxPrevious));
		printf("ListItem3->pxPrevious                   %#x         \r\n",(int)(ListItem3.pxPrevious));		
		
		printf("-------------------------结束---------------------- \r\n");

尾部插入列表项

void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )

		TestList.pxIndex = TestList.pxIndex->pxNext;
		vListInsertEnd(&TestList,&ListItem2);
		printf("-----------------删除列表项ListTtem3--------------- \r\n");
		printf("项目                                    地址        \r\n");
		printf("TestList->xlistEnd->pxNext              %#x         \r\n",(int)(TestList.xListEnd.pxNext));
		printf("ListItem1->pxNext                       %#x         \r\n",(int)(ListItem1.pxNext));
		printf("ListItem2->pxNext                       %#x         \r\n",(int)(ListItem2.pxNext));
		printf("ListItem3->pxNext                       %#x         \r\n",(int)(ListItem3.pxNext));
	
		printf("------------------前后连接分割线-------------------- \r\n");
		printf("TestList->xListEnd.pxPrevious           %#x         \r\n",(int)(TestList.xListEnd.pxPrevious));
		printf("ListItem1->pxPrevious                   %#x         \r\n",(int)(ListItem1.pxPrevious));
		printf("ListItem2->pxPrevious                   %#x         \r\n",(int)(ListItem2.pxPrevious));
		printf("ListItem3->pxPrevious                   %#x         \r\n",(int)(ListItem3.pxPrevious));		
		
		printf("-------------------------结束---------------------- \r\n");

任务查询与信息统计

得到任务优先级

UBaseType_t uxTaskPriorityGet( TaskHandle_t xTask )
此函数用来获取指定任务的优先级,要使用此函数的话宏 INCLUDE_uxTaskPriorityGet 应该定义为 1

	UBaseType_t Priority;
	Priority = uxTaskPriorityGet(LISTTask_Handler);	
	printf("任务优先级:%d  \r\n",(int)Priority);

得到任务状态

UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray, 
								  const UBaseType_t uxArraySize, 
								  uint32_t * const pulTotalRunTime )

此函数用于获取系统中所有任务的任务壮态,每个任务的壮态信息保存在一个 TaskStatus_t类型的结构体里面,这个结构体里面包含了任务的任务句柄、任务名字、堆栈、优先级等信息,要使用此函数的话宏 configUSE_TRACE_FACILITY 应该定义为 1。

		TaskStatus_t *TaskStatusArray;
		UBaseType_t ArraySize;
		uint32_t TotalRunTime;
		TaskStatusArray = pvPortMalloc(ArraySize*sizeof(TaskStatus_t));
		ArraySize = uxTaskGetNumberOfTasks();
		if(TaskStatusArray != NULL)
		{
				ArraySize = uxTaskGetSystemState( (TaskStatus_t *)  TaskStatusArray, 
																					(UBaseType_t)     ArraySize, 
																					(uint32_t *)      TotalRunTime );
				printf("TaskName\t\tTaskPri\t\ttNumber\t\t\r\n");
			
				for(int i=0;i<ArraySize;i++){
						printf("%s\t\t%d\t\t%d\t\t\r\n",
																		TaskStatusArray[i].pcTaskName,
																		(int)TaskStatusArray[i].uxCurrentPriority,
																		(int)TaskStatusArray[i].xTaskNumber);
				}
		}

获取当前任务的任务句柄

TaskHandle_t xTaskGetHandle( const char *pcNameToQuery )

此函数根据任务名字获取任务的任务句柄,在使用函数 xTaskCreate()或 xTaskCreateStatic()创建任务的时候都会给任务分配一个任务名,函数 xTaskGetHandle()就是使用这个任务名字来查询其对应的任务句柄的。要使用此函数的话宏 INCLUDE_xTaskGetHandle 应该设置为 1

		TaskHandle = xTaskGetHandle("LIST_task");
		printf("TaskHandle is %#x \r\n",TaskHandle);
		printf("TaskHandle is %#x \r\n",LISTTask_Handler);

堆栈历史剩余最小值

UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask )

每个任务都有自己的堆栈,堆栈的总大小在创建任务的时候就确定了,此函数用于检查任务从创建好到现在的历史剩余最小值,这个值越小说明任务堆栈溢出的可能性就越大!要使用此函数的话宏
INCLUDE_uxTaskGetStackHighWaterMark 必须为 1

while(1)
		{
			
				Stackmin = uxTaskGetStackHighWaterMark(LISTTask_Handler);
				printf("Stackmin is %d \r\n",Stackmin);
				vTaskDelay(500);
			
		}

任务状态

eTaskState eTaskGetState( TaskHandle_t xTask )

此函数用于查询某个任务的运行壮态,比如:运行态、阻塞态、挂起态、就绪态等,返回值是个枚举类型。要使用此函数的话宏 INCLUDE_eTaskGetState 必须为 1

		TaskState = eTaskGetState(Task1Task_Handler);
		
		printf("TaskState is %d \r\n",TaskState);

创建表格显示详细信息

void vTaskList( char * pcWriteBuffer )

此函数会创建一个表格来描述每个任务的详细信息

表中的信息如下:
Name: 创建任务的时候给任务分配的名字。
State: 任务的壮态信息,B 是阻塞态,R 是就绪态,S 是挂起态,D 是删除态。
Priority:任务优先级。
Stack: 任务堆栈的“高水位线”,就是堆栈历史最小剩余大小。
Num: 任务编号,这个编号是唯一的,当多个任务使用同一个任务名的时候可以通过此
编号来做区分。

		char InfoBuffer[1000];
		vTaskList(InfoBuffer);
		
		printf("%s\r\n",InfoBuffer);
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值