任务挂起和恢复API函数
下面用按键和震动传感器验证任务挂起和恢复API函数:
PA7接震动传感器,按键引脚为PA0,提前初始化好GPIO引脚
key.c
#include "key.h"
#include "stm32f10x.h"
void KeyInit()
{
GPIO_InitTypeDef KeyInitSruct;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE);
KeyInitSruct.GPIO_Mode = GPIO_Mode_IPU;
KeyInitSruct.GPIO_Pin = GPIO_Pin_7;
GPIO_Init(GPIOA,&KeyInitSruct);
KeyInitSruct.GPIO_Mode = GPIO_Mode_IPU;
KeyInitSruct.GPIO_Pin = GPIO_Pin_0;
GPIO_Init(GPIOA,&KeyInitSruct);
}
main.c
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
#include "key.h"
//开始任务
#define START_TASK_SIZE 256
#define START_TASK_PRIO 1
StackType_t StartTaskStack[START_TASK_SIZE];
StaticTask_t StartTask_TCB;
TaskHandle_t StartTask_Handle;
void start_task( void * pvParameters );
//任务1
#define TASK1_TASK_SIZE 120
#define TASK1_TASK_PRIO 4
StackType_t Task1TaskStack[TASK1_TASK_SIZE];
StaticTask_t Task1Task_TCB;
TaskHandle_t Task1Task_Handle;
void task1_task( void * pvParameters );
//任务2
#define TASK2_TASK_SIZE 120
#define TASK2_TASK_PRIO 3
StackType_t Task2TaskStack[TASK2_TASK_SIZE];
StaticTask_t Task2Task_TCB;
TaskHandle_t Task2Task_Handle;
void task2_task( void * pvParameters );
//任务3
#define KEY_TASK_SIZE 120
#define KEY_TASK_PRIO 2
StackType_t KeyaskStack[KEY_TASK_SIZE];
StaticTask_t KeyTask_TCB;
TaskHandle_t KeyTask_Handle;
void key_task( void * pvParameters );
//空闲任务
static StaticTask_t IdleTaskTCB;
static StackType_t IdleTaskStack[configMINIMAL_STACK_SIZE];
void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
StackType_t ** ppxIdleTaskStackBuffer,
uint32_t * pulIdleTaskStackSize )
{
*ppxIdleTaskTCBBuffer = &IdleTaskTCB;
*ppxIdleTaskStackBuffer = IdleTaskStack;
*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
}
//定时器任务
static StaticTask_t TimerTaskTCB;
static StackType_t TimerTaskStack[configTIMER_TASK_STACK_DEPTH];
void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer,
StackType_t ** ppxTimerTaskStackBuffer,
uint32_t * pulTimerTaskStackSize )
{
* ppxTimerTaskTCBBuffer = &TimerTaskTCB;
* ppxTimerTaskStackBuffer = TimerTaskStack;
*pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
}
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
delay_init(); //延时函数初始化
uart_init(115200); //串口初始化
LED_Init(); //LED初始化
KeyInit(); //引脚初始化
StartTask_Handle = xTaskCreateStatic( (TaskFunction_t) start_task,
(char * ) "start_task",
(uint32_t) START_TASK_SIZE,
(void *) NULL,
(UBaseType_t) START_TASK_PRIO,
(StackType_t *) StartTaskStack,
(StaticTask_t *) &StartTask_TCB );
vTaskStartScheduler(); //开启任务调度
}
//开始任务
void start_task( void * pvParameters )
{
while(1)
{
//任务1
Task1Task_Handle = xTaskCreateStatic( (TaskFunction_t) task1_task,
(char * ) "task1_task",
(uint32_t) TASK1_TASK_SIZE,
(void *) NULL,
(UBaseType_t) TASK1_TASK_PRIO,
(StackType_t *) Task1TaskStack,
(StaticTask_t *) &Task1Task_TCB );
//任务2
Task2Task_Handle = xTaskCreateStatic( (TaskFunction_t) task2_task,
(char * ) "task2_task",
(uint32_t) TASK2_TASK_SIZE,
(void *) NULL,
(UBaseType_t) TASK2_TASK_PRIO,
(StackType_t *) Task2TaskStack,
(StaticTask_t *) &Task2Task_TCB );
//任务3
KeyTask_Handle = xTaskCreateStatic( (TaskFunction_t) key_task,
(char * ) "key_task",
(uint32_t) KEY_TASK_SIZE,
(void *) NULL,
(UBaseType_t) KEY_TASK_PRIO,
(StackType_t *) KeyaskStack,
(StaticTask_t *) &KeyTask_TCB );
vTaskDelete(StartTask_Handle);
}
}
//任务1
void task1_task( void * pvParameters )
{
char Task1_num = 0;
while(1)
{
Task1_num++;
LED2 = !LED2;
vTaskDelay(1000);
printf("Task1 is Runing %d \r\n",Task1_num);
}
}
//任务2
void task2_task( void * pvParameters )
{
char Task2_num = 0;
while(1)
{
Task2_num++;
LED3 = !LED3;
vTaskDelay(1000);
printf("Task2 is Runing %d \r\n",Task2_num);
}
}
//任务3
void key_task( void * pvParameters )
{
while(1)
{
if( GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_7) == 0)
{
vTaskDelay(100);
vTaskSuspend(Task1Task_Handle);//当震动传感器工作将任务1挂起
printf("Task1 is Suspend! \r\n");
}
if( GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) == 0)
{
vTaskDelay(100);
vTaskResume(Task1Task_Handle);//当按键按下将任务1解挂
printf("Task1 is Resume! \r\n");
}
}
}
下面用串口验证:
下面我们在中断服务函数中恢复任务1:
xTaskResumeFromISR();该函数的参数依旧是任务句柄,但是该函数有两个返回值
返回值:
pdTRUE: 恢复运行的任务的任务优先级等于或者高于正在运行的任务(被中断打
断的任务),这意味着在退出中断服务函数以后必须进行一次上下文切换。
pdFALSE: 恢复运行的任务的任务优先级低于当前正在运行的任务(被中断打断的
任务),这意味着在退出中断服务函数的以后不需要进行上下文切换。
修改main.c:当震动传感器工作将任务1挂起
//任务3
void key_task( void * pvParameters )
{
while(1)
{
if( GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_7) == 0)
{
vTaskDelay(100);
vTaskSuspend(Task1Task_Handle);
printf("Task1 is Suspend! \r\n");
}
}
}
exti.c:
#include "exti.h"
#include "stm32f10x.h"
#include "FreeRTOS.h"
#include "task.h"
#include "delay.h"
void EXTIInit(void)
{
EXTI_InitTypeDef Exti_Initstruct;
NVIC_InitTypeDef NVIC_Initstruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
Exti_Initstruct.EXTI_Line = EXTI_Line0;
Exti_Initstruct.EXTI_LineCmd = ENABLE;
Exti_Initstruct.EXTI_Mode = EXTI_Mode_Interrupt;
Exti_Initstruct.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_Init(&Exti_Initstruct);
NVIC_Initstruct.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_Initstruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Initstruct.NVIC_IRQChannelPreemptionPriority = 6;//定义抢占优先级为6,小于5的中断不受FreeRtos管控!
NVIC_Initstruct.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&NVIC_Initstruct);
}
extern TaskHandle_t Task1Task_Handle;
void EXTI0_IRQHandler()//外部中断函数
{
BaseType_t YieldRequired;
delay_xms(20);//消抖
if ( EXTI_GetITStatus(EXTI_Line0) != RESET) //检测中断标志位
{
YieldRequired = xTaskResumeFromISR(Task1Task_Handle);//恢复任务1
printf("恢复任务1的运行! \r\n");
if(YieldRequired == pdTRUE)//如果函数返回值是pdTRUE,进行一次上下文切换
{
portYIELD_FROM_ISR(YieldRequired);//上下文切换函数
}
}
EXTI_ClearITPendingBit(EXTI_Line0);//清除中断
}
下面用串口验证结果: