任务简介
任务大体上与上一篇文章的任务差不多,但是将PB1连接的按键用来挂起任务,PB11的按键用来恢复任务,PB4的按键用中断恢复任务(使用xTaskResumeFromISR函数)。
任务创建
复制上一篇文章的FreeRTOS_任务创建与删除(动态)文件夹,粘贴后改名为FreeRTOS_任务创建与恢复,进入keil。
代码编写
由于PB4引脚是JTAG引脚,所以在使用PB4引脚前要先释放该引脚,然后配置中断,具体函数如下,笔者是直接将它加在了Key.c这个文件里的:
void PB4_EXTI_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; // 1. 使能GPIOB、AFIO复用时钟(EXTI必须AFIO时钟) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); // 2. 关闭JTAG,释放PB3/PB4引脚(F1必须加,否则PB4无法做普通IO) GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); // 3. 配置PB4 GPIO模式:上拉输入 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 内部上拉输入 GPIO_Init(GPIOB, &GPIO_InitStructure); // 4. 配置EXTI中断线:PB4映射到EXTI4 GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource4); EXTI_InitStructure.EXTI_Line = EXTI_Line4; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; // 下降沿触发 EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); // 5. NVIC中断优先级配置 NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x06; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); }随后在key.h这个函数里声明PB4_EXTI_Init函数,使得外部能够调用该函数。
随后打开FreeRTOS_Task.c文件,由于我们定义了PB4_EXTI_Init函数,所以我们要引用该函数,笔者是直接将他加在别的初始化函数下方,如下方代码所示
void FreeRTOS_Task(void) { Key_Init(); LED_Init(); PB4_EXTI_Init(); xTaskCreate( (TaskFunction_t ) Start_task, (char * ) "Start_task", (configSTACK_DEPTH_TYPE) START_TASK_SIZE, (void * ) NULL, (UBaseType_t ) START_TASK_PRIO, (TaskHandle_t * ) &start_task_handle ); vTaskStartScheduler(); }随后更改一下task_3函数中的部分语句即可,即将PA1所接按键的事件改为触发vTaskSuspend函数,既将task_1任务挂起,将PA1所接按键的事件改为触发vTaskResume函数,既将task_1任务恢复,参考代码如下:
void task_3( void * pvParameters ) { uint8_t KeyVal = 0; while(1) { KeyVal = Key_GetNum(); if(KeyVal != 0) { vTaskDelay(pdMS_TO_TICKS(20)); // RTOS延时,让出CPU,LED正常闪烁 if(Key_GetNum() == KeyVal) // 二次确认消抖 { // 等待按键松开 while(Key_GetNum() != 0) { vTaskDelay(pdMS_TO_TICKS(10)); } vTaskDelay(pdMS_TO_TICKS(20)); // 按键触发逻辑 if(KeyVal == 1) { vTaskSuspend(task1_handle); } else if(KeyVal == 2) { vTaskResume(task1_handle); } } } vTaskDelay(pdMS_TO_TICKS(10)); } }随后我们就可以写中断函数了,在FreeRTOS_Task.c 文件最后添加EXTI4_IRQHandler中断函数,用来使得PB4触发xTaskResumeFromISR函数,具体代码如下:
void EXTI4_IRQHandler(void) { BaseType_t xNeedSwitch = pdFALSE; if(EXTI_GetITStatus(EXTI_Line4) != RESET) { // 硬件消抖:确认PB4低电平(按键按下) if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_4) == 0) { // 中断专用恢复任务API xNeedSwitch = xTaskResumeFromISR(task1_handle); } EXTI_ClearITPendingBit(EXTI_Line4); //清除中断标志位 } // 若唤醒更高优先级任务,立即切换上下文 portYIELD_FROM_ISR(xNeedSwitch); }最后编译后下载即可实现现象。
若有错误,还望海涵。