FreeRTOS系列六:任务的挂起与恢复的API函数(实战附代码)

实验现象:按键KEY1按下执行挂起任务一,按键KEY2按下执行挂起任务二,按键WK_UP按下恢复任务一

同时在任务一执行时LCD屏幕上显示TASK1 runing,任务二执行时LCD屏幕上显示TASK2 runing。串口实时打印按键数据。

贴一下main.c,完整代码链接在最后

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
#include "lcd.h"
#include "key.h"
/************************************************
 ALIENTEK 战舰STM32F103开发板 FreeRTOS实验2-1
 FreeRTOS移植实验-库函数版本
 技术支持:www.openedv.com
 淘宝店铺:http://eboard.taobao.com 
 关注微信公众平台微信号:"正点原子",免费获取STM32资料。
 广州市星翼电子科技有限公司  
 作者:正点原子 @ALIENTEK
************************************************/

//任务优先级
#define START_TASK_PRIO		1
//任务堆栈大小	
#define START_STK_SIZE 		128  
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);

//任务优先级
#define KEY_TASK_PRIO		2
//任务堆栈大小	
#define KEY_STK_SIZE 		128  
//任务句柄
TaskHandle_t KeyTask_Handler;
//任务函数
void key_task(void *pvParameters);


//任务优先级
#define LED0_TASK_PRIO		3
//任务堆栈大小	
#define LED0_STK_SIZE 	 128  
//任务句柄
TaskHandle_t LED0Task_Handler;
//任务函数
void led0_task(void *pvParameters);

//任务优先级
#define LED1_TASK_PRIO		4
//任务堆栈大小	
#define LED1_STK_SIZE 		128  
//任务句柄
TaskHandle_t LED1Task_Handler;
//任务函数
void led1_task(void *pvParameters);
u8 key=0;
int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4	 
	delay_init();	    				//延时函数初始化	  
	uart_init(115200);					//初始化串口
	LED_Init();		  					//初始化LED
	LCD_Init();			   	//初始化LCD
	KEY_Init();         //初始化按键
	
	 
	//创建开始任务
    xTaskCreate((TaskFunction_t )start_task,            //任务函数
                (const char*    )"start_task",          //任务名称
                (uint16_t       )START_STK_SIZE,        //任务堆栈大小
                (void*          )NULL,                  //传递给任务函数的参数
                (UBaseType_t    )START_TASK_PRIO,       //任务优先级
                (TaskHandle_t*  )&StartTask_Handler);   //任务句柄              
    vTaskStartScheduler();          //开启任务调度
}

//开始任务任务函数
void start_task(void *pvParameters)
{
	
    taskENTER_CRITICAL();           //进入临界区
	//创建KEY任务
	xTaskCreate((TaskFunction_t )key_task,             
                (const char*    )"key_task",           
                (uint16_t       )KEY_STK_SIZE,        
                (void*          )NULL,                  
                (UBaseType_t    )KEY_TASK_PRIO,        
                (TaskHandle_t*  )&KeyTask_Handler);   
    //创建LED0任务
    xTaskCreate((TaskFunction_t )led0_task,     	
                (const char*    )"led0_task",   	
                (uint16_t       )LED0_STK_SIZE, 
                (void*          )NULL,				
                (UBaseType_t    )LED0_TASK_PRIO,	
                (TaskHandle_t*  )&LED0Task_Handler);   
    //创建LED1任务
    xTaskCreate((TaskFunction_t )led1_task,     
                (const char*    )"led1_task",   
                (uint16_t       )LED1_STK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )LED1_TASK_PRIO,
                (TaskHandle_t*  )&LED1Task_Handler);         
    vTaskDelete(StartTask_Handler); //删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
}

//key任务函数
void key_task(void *pvParameters)
{
	u8 key;
	while(1)
	{
        key = KEY_Scan(0);
				if (key == KEY1_PRES)
				{
					if (LED0Task_Handler != NULL)
					{						

				    vTaskSuspend(LED0Task_Handler);//挂起任务1
				    printf("挂起任务1的运行!\r\n");
					}
				}
				else if (key == WKUP_PRES)
				{
					if (LED0Task_Handler != NULL)
					{
				    vTaskResume(LED0Task_Handler);	//恢复任务1
				    printf("恢复任务1的运行!\r\n");
					}
				}else if(key ==KEY2_PRES)
				{
					if (LED0Task_Handler != NULL)
					{
						vTaskSuspend(LED1Task_Handler);//挂起任务2
						printf("挂起任务2的运行!\r\n");
					}
				}
				
		vTaskDelay(10);			//延时10ms 
	}
}


//LED0任务函数 
void led0_task(void *pvParameters)
{
    u8 float_num=0;
    while(1)
    {
        float_num++;
        taskENTER_CRITICAL();           //进入临界区
			  printf("任务一正在运行\r\n"); 
        printf("任务一运行的次数为: %d次\r\n",float_num);   /*串口打印结果*/
        taskEXIT_CRITICAL();            //退出临界区
				LCD_Clear(WHITE);
			  LCD_DrawFont_GBK16(4, 50, BLACK, WHITE,"TASK1 runing");	 

				
				vTaskDelay(1000);
	
    }
}   

//LED1任务函数
void led1_task(void *pvParameters)
{
	  u8 task2_num=0;
    while(1)
    {  	
			  task2_num++;
			  LCD_Clear(WHITE);
			  LCD_DrawFont_GBK16(4, 50, BLUE, WHITE,"TASK2 runing");
        LED0=!LED0;
		    printf("任务二正在运行灯\r\n");
			  printf("任务二运行的次数为: %d次\r\n",task2_num);   /*串口打印结果*/
        vTaskDelay(1000);
    }

}

再贴一下中断的代码,这里在使用wake_up按键来控制TASK2在中断中的恢复有点问题,这里按键是上升沿出发的,但是在恢复时串口会打印出一点错误

这是刚开始时运行的问题

Error:..\FreeRTOS\portable\RVDS\ARM_CM3\port.c,380

解救方法:把代码中用到delay函数的地方改为不影响调度的delay_xms()就好

eg:delay_xms(10);//延时函数消抖

//延时nms,不会引起任务调度
//nms:要延时的ms数
void delay_xms(u32 nms)
{
	u32 i;
	for(i=0;i<nms;i++) delay_us(1000);
}

#include "exti.h"
#include "led.h"
#include "key.h"
#include "delay.h"
#include "FreeRTOS.h"
#include "task.h"
//	 
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK战舰STM32开发板
//外部中断 驱动代码	   
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2012/9/3
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2009-2019
//All rights reserved									  
//   

//外部中断0服务程序
void EXTIX_Init(void)
{
 
 	  EXTI_InitTypeDef EXTI_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    KEY_Init();	 //	按键端口初始化

  	//RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);	//使能复用功能时钟

   //GPIOE.4	  中断线以及中断初始化配置  下降沿触发	//KEY0
  	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);

	  EXTI_InitStructure.EXTI_Line=EXTI_Line0;
  	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	
  	EXTI_InitStructure.EXTI_Trigger =EXTI_Trigger_Rising ;
  	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  	EXTI_Init(&EXTI_InitStructure);	 	//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器

	  NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;				//使能按键KEY0所在的外部中断通道
  	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x08;	//抢占优先级6
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x06;			//子优先级0 
  	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;					//使能外部中断通道
  	NVIC_Init(&NVIC_InitStructure);  	  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
 
}

//任务句柄
extern TaskHandle_t LED1Task_Handler;

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

  

链接:https://pan.baidu.com/s/1DZ1kKHLZdiKwuCnNHp1kGQ?pwd=rtos 
提取码:rtos

Error:..\FreeRTOS\portable\RVDS\ARM_CM3\port.c,378 Error:..\FreeRTOS\portable\RVDS\ARM_CM3\port.c,378 Error:..\FreeRTOS\portable\RVDS\ARM_CM3\port.c,378 Error:..\FreeRTOS\tasks.c,2806 - 避暑山庄 - 博客园 (cnblogs.com)

猜你喜欢

转载自blog.csdn.net/qq_51519091/article/details/131504149