• STM32第二十课:FreeRTOS任务管理和信号量



    一、任务管理方式

    在这里插入图片描述
    1.任务创建成功后会添加到就绪链表中,开启调度器,此时任务调度器会去就绪链表中找优先级最高的任务执行。若优先级一样则按照创建任务的先后来执行。
    2.任务被执行时就会变为运行态时,该任务就会从就绪链表删除,若此时执行到任务中的vTaskDelay等函数时,该任务就会被挪到阻塞链表中。调度器此时会去执行其他任务。
    3.当阻塞解除时,该任务会从阻塞链表中删掉,移动到就绪链表中。若解除任务的优先级很高,那么此时该任务会直接打断cpu正在执行的任务,抢占位置去执行自己。

    二、任务堆栈溢出检测

    详情见FreeRTOS中的任务堆栈溢出检测机制
    主要作用就是方便调试,工程做完之后没问题了就关掉
    写检测函数之前需要更改宏定义,我们采用的是第二种堆栈检测方法。
    ![

    void vApplicationStackOverflowHook( TaskHandle_t xTask,char *pcTaskName )
    {
    	printf("任务:%s->栈溢出\r\n",pcTaskName);
    	printf("任务剩余空间:%d\r\n",(int)uxTaskGetStackHighWaterMark(xTask));
    	while(1)//栈溢出时卡死到钩子函数中
    	{}
    }
    

    本质上就是一个钩子函数,在任务上下文切换的时候做检测,具有一定的滞后性,需要在任务发生上下文切换时才会进行,任务堆栈溢出时并不能马上检测到问题。
    但大多常见情况下这种检测机制依然是非常实用的功能,可以帮助用户减少代码中的错误并提高应用程序代码的质量。

    三、二值信号量(任务同步)

    任务同步:任务B需要等待任务A执行完再去执行。
    二值信号量也一样,谁拥有谁执行,比如任务B需要获得信号量才能执行,那么他就要等待A给他一个信号量然后再去执行。

    1.添加头文件

    #include "semphr.h"
    

    2.创建一个SemaphoreHandle_t 类型的二值信号量句柄

    SemaphoreHandle_t Binary;
    

    3.主函数创建二值信号量,返回值为该信号量的句柄

    	//创建一个二值信号量
    	Binary = xSemaphoreCreateBinary();
    

    4.使用函数xSemaphoreGive给出二值信号量,参数为二值信号量的句柄

    xSemaphoreGive(Binary)
    

    5.使用xSemaphoreTake函数接收二值信号量,参数为句柄和超时时间(也可填写portMAX_DELAY,表示死等)
    若返回值为pdTRUE,则表示获取到该信号量。

    if(xSemaphoreTake(Binary,1000) == pdTRUE) 
    		{
    			printf("按键按下,获取到信号量\r\n");
    		}
    

    完整代码

    //包含支持stm32f1系列的头文件
    #include  "stm32f10x.h"
    #include "led.h"
    #include "delay.h"
    #include "usart.h"
    #include "key.h"
    #include "adc.h"
    #include "kqm.h"
    #include "dht11.h"
    
    //使用FreeRTOS相关头文件之前先包含FreeRTOS.h
    #include "FreeRTOS.h"
    #include "task.h"
    #include "semphr.h"
    /********************信号量句柄***********************/
    SemaphoreHandle_t Binary;
    
    //传感器任务
    TaskHandle_t Sensor_TaskHandle;
    void Sensor_Task(void *p)
    {
    	
    	while(1)
    	{
    		taskENTER_CRITICAL();//进入临界区
    		Dht11ReadData();//DHT11读取函数不能被打断
    		taskEXIT_CRITICAL();//退出临界区
    		KQMDealData();//该函数的调用时间小于等于1秒
    		ADC_DataFliter();//ADC均值滤波
    		vTaskDelay(1000);//阻塞1秒
    	}
    }
    
    //任务本体 闪灯任务
    TaskHandle_t LED_TaskHandle;
    void LED_Task(void *p)
    {
    	uint8_t i=0;
    	while(1)
    	{
    		if(xSemaphoreTake(Binary,1000) == pdTRUE) 
    		{
    			printf("按键按下,获取到信号量\r\n");
    		}else
    		{
    			printf("获取到信号量等待超时\r\n");
    		}
    		i++;
    		printf("i=%d\r\n",i);
    		Led_Toggle(1);
    		//printf("LED任务剩余空间:%d\r\n",(int)uxTaskGetStackHighWaterMark(NULL));
    //		Delay_nms(200);//也能延时,但是会一直占用CPU
    		//也是延时200ms,但是FreeRTOS提供的函数,有阻塞机制,能够让任务从运行态变为阻塞态
    		vTaskDelay(200);
    	}
    }
    //任务本体 按键任务
    TaskHandle_t KEY_TaskHandle;
    void KEY_Task(void *p)
    {
    	while(1)
    	{
    		switch(key_getvalue())
    		{
    			case 1:vTaskSuspend(LED_TaskHandle);break;
    			case 2:vTaskResume(LED_TaskHandle);break;
    			case 3:xSemaphoreGive(Binary);break;
    			case 4:break;
    		}
    		vTaskDelay(10);//MS级别的延时,带有阻塞性质,任务会从运行态变为阻塞态
    	}
    }	
    
    int main()
    {
    	Led_Init();//初始化LED
    	Key_init();//初始化按键
    	Usart1_Config();//初始化串口1
    	ADC_Config();//初始化ADC
    	Kqm_U4Config();//初始化KQM
    	DHT11_Mode();//初始化DHT11
    	BaseType_t Ret = pdPASS;
    	//创建一个二值信号量
    	Binary = xSemaphoreCreateBinary();
    	//1,如何创建一个任务?
    	Ret = xTaskCreate(Sensor_Task,"Sensor_Task",200,NULL,1,&Sensor_TaskHandle);
    	Ret = xTaskCreate(LED_Task, //创建任务的任务函数名
                        "LED1_Toggle",//任务名字
                        100,//任务栈深度。32位单片机*4
                        NULL,//创建任务时传递参数,没有就给NULL
                        3,//任务优先级
    										&LED_TaskHandle);//任务的句柄,用于后边删除,挂起任务
    	if(Ret == pdPASS){
    		printf("LED_Task创建完成\r\n");
    	}
    	Ret = xTaskCreate(KEY_Task, //创建任务的任务函数名
                        "KEY_Task",//任务名字
                        100,//任务栈深度。32位单片机*4
                        NULL,//创建任务时传递参数,没有就给NULL
                        2,//任务优先级
    										&KEY_TaskHandle);//任务的句柄,用于后边删除,挂起任务
    	if(Ret == pdPASS){
    		printf("KEY_Task创建完成\r\n");
    	}
    	printf("开启FreeRTOS调度器\r\n");
    	//调度器启动完成之后,FreeRTOS会获取CPU控制权,会按照任务优先级执行创建的任务
    	vTaskStartScheduler();
    				
    	while(1)
    	{	
    	}
    }
    
    void vApplicationStackOverflowHook( TaskHandle_t xTask,char *pcTaskName )
    {
    	printf("任务:%s->栈溢出\r\n",pcTaskName);
    	printf("任务剩余空间:%d\r\n",(int)uxTaskGetStackHighWaterMark(xTask));
    	while(1)//栈溢出时卡死到钩子函数中
    	{}
    }
    
    
    

    四、计数信号量

    一般在资源有限的情况下使用,如:停车场,坐位,传感器的访问等。
    计数信号量测试:按键和灯,按键按下几次,灯翻转几次。
    1.创建计数信号量的句柄

    SemaphoreHandle_t Count_Handle;//计数信号量句柄
    

    2.创建计数信号量
    返回值为该信号量的句柄,参数为最大信号量为多少和初始信号量有几个。

    Count_Handle = xSemaphoreCreateCounting(10,5);//创建计数信号量
    

    3.给出信号量
    参数为计数信号量的句柄

    xSemaphoreGive(Count_Handle);
    

    4.消耗信号量
    参数和二值信号量一样,一个是对应的句柄,一个是超时。
    成功返回pdTRUE。

    if(xSemaphoreTake(Count_Handle,portMAX_DELAY) == pdTRUE) 
    

    完整代码

    #include "stm32f10x.h"
    #include "led.h"
    #include "delay.h"
    #include "delay.h"
    #include "string.h"
    #include "pwm.h"
    #include "adc.h"
    #include "su03t.h"
    #include "dht11.h"
    #include "kqm.h"
    #include "usart.h"
    #include "key.h"
    
    //使用FreeRtos相关头文件之前,一定要先包含这个#include "FreeRtos.h"
    #include "FreeRtos.h"
    #include "task.h"
    #include "semphr.h"
    #include "queue.h"
    
    TaskHandle_t Deal_TaskHandle;//数据处理
    SemaphoreHandle_t Binary;//二值信号量句柄
    SemaphoreHandle_t Count_Handle;//计数信号量句柄
    TaskHandle_t LED_TaskHandle;//任务本体 闪灯任务
    TaskHandle_t KEY_TaskHandle;//任务本体 按键任务
    void Data_Task(void *p)
    {
    	while(1)
    	{
    	Get_Smoke_Light_MidValue();
    	DHT11_ReadData();
    	vTaskDelay(300);
    	KQM_DealData();
    	Su03tDealData();
    	}
    }
    
    void KEY_Task(void *p)
    {
    	while(1)
    	{
    		switch(key_getvalue())
    		{
    			case 1:vTaskSuspend(LED_TaskHandle);break;
    			case 2:vTaskResume(LED_TaskHandle);break;
    			case 3:xSemaphoreGive(Count_Handle);printf("给一个计数信号量\r\n");break;
    			case 4:break;
    		}
    		vTaskDelay(10);//MS级别的延时,带有阻塞性质,任务会从运行态变为阻塞态
    	}
    }	
    void LED_Task(void *p)
    {
    	uint8_t i=0;
    	while(1)
    	{
    		if(xSemaphoreTake(Count_Handle,portMAX_DELAY) == pdTRUE) 
    		{
    			printf("消耗计数信号量\r\n");
    			i++;
    			printf("i=%d\r\n",i);
    			Led_Toggle(1);
    			vTaskDelay(1000);
    		}
    	}
    }
    
    
    
    int main()
    {
    	RGBpwm_Config();
      Kqm_U4Config();
      Su03t_U5Config();
    	DHT11_Config();	 
    	Adc_Config();
    	Led_Init();
    	key_Init();
    	Usart1_Config();
    	BaseType_t Ret = pdPASS;
    //	Ret = xTaskCreate(Data_Task,"DealData",300,NULL,2,&Deal_TaskHandle);
    //	if(Ret==pdPASS)
    //	{
    //		printf("数据创建成功!\r\n");
    //	}
    	Binary = xSemaphoreCreateBinary();
    	//计数信号量最大值   初始时有多少个信号量可用
    	Count_Handle = xSemaphoreCreateCounting(10,5);//创建计数信号量
    		Ret = xTaskCreate(LED_Task, //创建任务的任务函数名
                        "LED1_Toggle",//任务名字
                        100,//任务栈深度。32位单片机*4
                        NULL,//创建任务时传递参数,没有就给NULL
                        3,//任务优先级
    										&LED_TaskHandle);//任务的句柄,用于后边删除,挂起任务
    	if(Ret == pdPASS){
    		printf("LED_Task创建完成\r\n");
    	}
    	Ret = xTaskCreate(KEY_Task, //创建任务的任务函数名
                        "KEY_Task",//任务名字
                        100,//任务栈深度。32位单片机*4
                        NULL,//创建任务时传递参数,没有就给NULL
                        2,//任务优先级
    										&KEY_TaskHandle);//任务的句柄,用于后边删除,挂起任务
    	if(Ret == pdPASS){
    	printf("KEY_Task创建完成\r\n");
    	}
    	printf("开启FreeRTOS调度器成功\r\n");
    	vTaskStartScheduler();
    	while(1)
    	{
    		
    	}
    }
    
    void vApplicationStackOverflowHook( TaskHandle_t xTask,char *pcTaskName )
    {
    	printf("任务:%s->栈溢出\r\n",pcTaskName);
    	printf("任务剩余空间:%d\r\n",(int)uxTaskGetStackHighWaterMark(xTask));
    	while(1)//栈溢出时卡死到钩子函数中
    	{}
    }
    
    

    五、互斥信号量

    用于共享资源的保护
    资源A是共享资源,此时如果被任务1使用,那么就不能被其他任务使用。
    (任务1:小A,你让我使用了,可就不能让别人使用了哦 ~)
    1.创建句柄

    SemaphoreHandle_t Mutex_Handle=NULL;
    

    2.创建互斥信号量
    返回值为互斥信号量的句柄

    Mutex_Handle = xSemaphoreCreateMutex();//创建互斥信号量
    

    3.获取信号,给出信号
    保护printf,使printf能够完整打印。

    void MyPrintf(char *p)
    {
    	xSemaphoreTake(Mutex_Handle,portMAX_DELAY);//获取信号量
    	printf("%s",p);
    	xSemaphoreGive(Mutex_Handle);//还回去
    }
    

    完整代码:

    #include "delay.h"
    #include "FreeRTOS.h"
    #include "task.h"
    #include "semphr.h"
    #include "usart.h"
    #include "stdio.h"
    #include "led.h"
    #include "key.h"
    #include "dht.h"
    #include "adc.h"
    #include "kqm.h"
    
    /*******************信号量句柄*********************/
    SemaphoreHandle_t Binary_Handle=NULL;
    SemaphoreHandle_t Count_Handle=NULL;
    SemaphoreHandle_t Mutex_Handle=NULL;
    /*******************互斥信号量保护资源*********************/
    void MyPrintf(char *p)
    {
    	xSemaphoreTake(Mutex_Handle,portMAX_DELAY);//获取信号量
    	printf("%s",p);
    	xSemaphoreGive(Mutex_Handle);//还回去
    }
    
    /*******************LED任务*********************/
    TaskHandle_t LEDtask_Handle = NULL;
    //任务函数本身
    void LED_Task(void * p)
    {
    	MyPrintf("LED任务创建成功\r\n");
    	LED_Config();
    	BEEP_Config();
    	while(1)
    	{	
    		if(xSemaphoreTake(Count_Handle,portMAX_DELAY) == pdTRUE)
    		{
    			MyPrintf("LED反转\r\n");
    			LED1_Toggle();
    		}else
    		{
    			MyPrintf("超时结束\r\n");
    		}
    		vTaskDelay(500);//控制任务的执行周期
    	}
    }
    /*******************按键任务*********************/
    TaskHandle_t KEYtask_Handle = NULL;
    //任务函数本身
    void KEY_Task(void * p)
    {
    	MyPrintf("按键任务创建成功\r\n");
    	KEY_Config();
    	while(1)
    	{	
    		switch(KEY_Scan())
    		{
    			case 1:BEEP_Toggle(); break;
    			case 2:
    //				xSemaphoreGive(Binary_Handle);//给出二值信号量
    				if(xSemaphoreGive(Count_Handle) == pdTRUE)//给出计数信号量
    				{
    					MyPrintf("成功给出计数信号量\r\n");
    				}else
    				{
    					MyPrintf("信号量已满\r\n");
    				}
    				break;
    			case 3: break;
    			case 4:vTaskDelete(LEDtask_Handle);break;
    		}
    		vTaskDelay(10);
    	}
    }
    /*******************传感器任务*********************/
    TaskHandle_t Senortask_Handle = NULL;
    //任务函数本身
    void Senor_Task(void * p)
    {
    	MyPrintf("传感器任务创建成功\r\n");
    	uint8_t cnt = 0;
    	ADC_Config();//初始化ADC
    	UART4_Config();//初始化KQM传感器
    	while(1)
    	{	
    		cnt++;
    		if(KQM_Anlyze() == 0)
    		{
    			printf("CO2:%d\r\n",kqmdata.CO2);
    		}else
    		{
    			MyPrintf("KQM数据错误\r\n");
    		}
    		if(cnt>=3)
    		{
    			cnt = 0;
    			taskENTER_CRITICAL();//进入临界区
    			if(DHT11_ReadData()== 0)
    			{
    				printf("温度数据:%.2f 湿度数据:%d\r\n",TEM,HUM);
    			}else
    			{
    				MyPrintf("温湿度数据获取失败\r\n");
    			}
    			taskEXIT_CRITICAL();//退出临界区			
    		}
    		vTaskDelay(1000);
    	}
    }
    int main(void)
    {
    	USART_Config();
    	BaseType_t Ret = pdPASS;
    	Binary_Handle = xSemaphoreCreateBinary();//创建二值信号量
    	//                       计数信号量最大值   初始时有多少个信号量可用
    	Count_Handle = xSemaphoreCreateCounting(10,5);//创建计数信号量
    	Mutex_Handle = xSemaphoreCreateMutex();//创建互斥信号量
    	//动态创建任务
    	Ret =  xTaskCreate(LED_Task,//任务函数的入口,也就是函数名
                         "LED_Task",//任务别名,方便FreeRTOS管理
                         100,//任务分配的堆栈空间 32单片机就是50*4 = 200字节
                         NULL,//任务函数的参数,无参数就写NULL
                         1,//任务优先级
                         &LEDtask_Handle);//任务的句柄(指针),可以用来管理任务
    	if(Ret == pdPASS)
    	{
    		printf("LED任务创建成功\r\n");
    	}
    	//动态创建任务
    	Ret =  xTaskCreate(KEY_Task,//任务函数的入口,也就是函数名
                         "KEY_Task",//任务别名,方便FreeRTOS管理
    											100,//任务分配的堆栈空间 32单片机就是50*4 = 200字节
                         NULL,//任务函数的参数,无参数就写NULL
                         1,//任务优先级
                         &KEYtask_Handle);//任务的句柄(指针),可以用来管理任务
    	if(Ret == pdPASS)
    	{
    		printf("按键任务创建成功\r\n");
    	}
    	Ret =  xTaskCreate(Senor_Task,//任务函数的入口,也就是函数名
                         "Senor_Task",//任务别名,方便FreeRTOS管理
                         100,//任务分配的堆栈空间 32单片机就是50*4 = 200字节
                         NULL,//任务函数的参数,无参数就写NULL
                         2,//任务优先级
                         &Senortask_Handle);//任务的句柄(指针),可以用来管理任务
    	if(Ret == pdPASS)
    	{
    		printf("传感器任务创建成功\r\n");
    	}
    	vTaskStartScheduler();//启动调度器
    	printf("调度器启动失败\r\n");
      while (1)
      {
    
    	}
    }
    
    //函 数 功 能:任务栈溢出钩子函数,调试阶段用
    void vApplicationStackOverflowHook(TaskHandle_t xTask,signed char *pcTaskName)
    {
    	printf("任务:#%s #栈溢出\r\n",pcTaskName);
    	printf("任务栈空间剩余:%d\r\n",uxTaskGetStackHighWaterMark(xTask));
    	while(1)
    	{
    	}
    }
    
    

    六、队列

      主要用于任务间数据传输,采用FIFO(先进先出)模式,新数据通常发到队列后面,但也可以发到队列前面。
    1.创建句柄

    QueueHandle_t Queue;
    

    2.创建队列

    //创建队列 长度为10 ,队列中每个数据的大小2字节
    	Queue = xQueueCreate(10,2);
    

    3.接收数据
    参数1:要发送数据的目标队列的句柄。
    参数2:指向要发送数据的指针。
    参数3:发送数据时等待的最长时间
    返回值:
    pdPASS:数据成功发送到队列。
    errQUEUE_FULL:队列已满,无法发送数据。

    if(xQueueReceive(Queue,buff2,100)==pdTRUE)
    

    4.发送数据

    if(xQueueSend(Queue,buff,100) == pdTRUE)
    

    完整代码:

    //包含支持stm32f1系列的头文件
    #include  "stm32f10x.h"
    #include "led.h"
    #include "delay.h"
    #include "usart.h"
    #include "key.h"
    #include "adc.h"
    #include "kqm.h"
    #include "dht11.h"
    
    //使用FreeRTOS相关头文件之前先包含FreeRTOS.h
    #include "FreeRTOS.h"
    #include "task.h"
    #include "semphr.h"
    /********************信号量句柄***********************/
    SemaphoreHandle_t Binary;
    SemaphoreHandle_t Count;
    SemaphoreHandle_t Mutex;
    /********************队列句柄***********************/
    QueueHandle_t Queue;
    QueueHandle_t KqmQueue;
    /*********************互斥锁保护Printf****************/
    void MyPrintf(char *p)
    {
    	xSemaphoreTake(Mutex,portMAX_DELAY);
    	printf("%s",p);
    	xSemaphoreGive(Mutex);
    }
    
    //传感器任务
    TaskHandle_t Sensor_TaskHandle;
    void Sensor_Task(void *p)
    {
    	uint8_t recv[8] = {0};
    	MyPrintf("Sensor Task Begin\r\n");
    	while(1)
    	{
    		if(xQueueReceive(KqmQueue,recv,100)==pdTRUE)
    		{
    			printf("接受数据:%x %x %x %x %x %x %x %x\r\n",recv[0],recv[1],\
    			recv[2],recv[3],recv[4],recv[5],recv[6],recv[7]);
    		}else
    		{
    			printf("队列为空,接收失败\r\n");
    		}
    		taskENTER_CRITICAL();//进入临界区
    		Dht11ReadData();//DHT11读取函数不能被打断
    		ADC_DataFliter();//ADC均值滤波
    		taskEXIT_CRITICAL();//退出临界区
    		vTaskDelay(1000);//阻塞1秒
    	}
    }
    
    //任务本体 闪灯任务
    TaskHandle_t LED_TaskHandle;
    void LED_Task(void *p)
    {
    	uint8_t i=0;
    	MyPrintf("LED_Task Begin\r\n");
    	while(1)
    	{
    		if(xSemaphoreTake(Count,portMAX_DELAY) == pdTRUE) 
    		{
    			MyPrintf("按键按下,获取到信号量\r\n");
    		}else
    		{
    			MyPrintf("获取到信号量等待超时\r\n");
    		}
    		printf("i=%d\r\n",i++);
    		Led_Toggle(1);
    		//printf("LED任务剩余空间:%d\r\n",(int)uxTaskGetStackHighWaterMark(NULL));
    //	Delay_nms(200);//也能延时,但是会一直占用CPU
    		//也是延时200ms,但是FreeRTOS提供的函数,有阻塞机制,能够让任务从运行态变为阻塞态
    		vTaskDelay(1000);
    	}
    }
    //任务本体 按键任务
    TaskHandle_t KEY_TaskHandle;
    void KEY_Task(void *p)
    {
    	uint8_t buff[2] = {0xAA,0x55};
    	uint8_t buff2[2] = {0};
    	MyPrintf("KEY_Task Begin\r\n");
    	while(1)
    	{
    		switch(key_getvalue())
    		{
    			case 1:
    				if(xQueueSend(Queue,buff,100) == pdTRUE)
    				{
    					printf("发送成功\r\n");
    				}else
    				{
    					printf("队列已满,发送失败\r\n");
    				}
    				break;
    			case 2:
    				if(xQueueReceive(Queue,buff2,100)==pdTRUE)
    				{
    					printf("接受数据:%x %x\r\n",buff2[0],buff2[1]);
    				}else
    				{
    					printf("队列为空,接收失败\r\n");
    				}
    				break;
    			case 3:xSemaphoreGive(Count);break;
    			case 4: break;
    		}
    		vTaskDelay(10);//MS级别的延时,带有阻塞性质,任务会从运行态变为阻塞态
    	}
    }	
    
    int main()
    {
    	Led_Init();//初始化LED
    	Key_init();//初始化按键
    	Usart1_Config();//初始化串口1
    	ADC_Config();//初始化ADC
    	Kqm_U4Config();//初始化KQM
    	DHT11_Mode();//初始化DHT11
    	BaseType_t Ret = pdPASS;
    	//创建一个二值信号量
    	Binary = xSemaphoreCreateBinary();
    	//创建一个计数信号量
    	Count = xSemaphoreCreateCounting(10,5);
    	//创建互斥锁
    	Mutex = xSemaphoreCreateMutex();
    	//创建队列 长度为10 ,队列中每个数据的大小2字节
    	Queue = xQueueCreate(10,2);
    	KqmQueue = xQueueCreate(1,8);
    	//1,如何创建一个任务?
    	Ret = xTaskCreate(Sensor_Task,"Sensor_Task",200,NULL,1,&Sensor_TaskHandle);
    //	Ret = xTaskCreate(LED_Task, //创建任务的任务函数名
    //                    "LED1_Toggle",//任务名字
    //                    100,//任务栈深度。32位单片机*4
    //                    NULL,//创建任务时传递参数,没有就给NULL
    //                    1,//任务优先级
    //										&LED_TaskHandle);//任务的句柄,用于后边删除,挂起任务
    //	if(Ret == pdPASS){
    //		printf("LED_Task创建完成\r\n");
    //	}
    	Ret = xTaskCreate(KEY_Task, //创建任务的任务函数名
                        "KEY_Task",//任务名字
                        100,//任务栈深度。32位单片机*4
                        NULL,//创建任务时传递参数,没有就给NULL
                        1,//任务优先级
    										&KEY_TaskHandle);//任务的句柄,用于后边删除,挂起任务
    	if(Ret == pdPASS){
    		printf("KEY_Task创建完成\r\n");
    	}
    	printf("开启FreeRTOS调度器\r\n");
    	//调度器启动完成之后,FreeRTOS会获取CPU控制权,会按照任务优先级执行创建的任务
    	vTaskStartScheduler();
    	printf("开启FreeRTOS调度器成功\r\n");
    	while(1)
    	{	
    	}
    }
    
    void vApplicationStackOverflowHook( TaskHandle_t xTask,char *pcTaskName )
    {
    	printf("任务:%s->栈溢出\r\n",pcTaskName);
    	printf("任务剩余空间:%d\r\n",(int)uxTaskGetStackHighWaterMark(xTask));
    	while(1)//栈溢出时卡死到钩子函数中
    	{}
    }
    
  • 相关阅读:
    Java项目:SSM电器商城系统
    基于Go语言Iris+Xorm搭建MVC项目教程
    关于一些常见/好用的matlab工具箱介绍
    Spring总结1.0
    不得不会的Oracle数据库知识点(二)
    将Vite添加到您现有的Web应用程序
    【微信开发第四章】SpringBoot实现微信H5支付
    多路转接(使用epoll实现)
    vue+flask微博大数据舆情监控+情感分析可视化系统+爬虫
    实现一个类 支持100个线程同时向银行账户存入一元钱
  • 原文地址:https://blog.csdn.net/Jokerblank/article/details/140418120