需求
创建 4 个任务:TaskLED_1,TaskLED_2,TaskKEY_1,TaskKEY_2
任务要求如下:
TaskLED_1:间隔 500ms 闪烁 LED1
TaskLED_2:间隔 1000ms 闪烁 LED2
TaskKEY_1:如果 taskLED1 存在,则按下 KEY1 后删除 taskLED1 ,否则创建 taskLED1
TaskKEY_2:如果 taskLED2 正常运行,则按下 KEY2 后挂起 taskLED2 ,否则恢复 taskLED2
CubeMX
直接在上上节的“mjm_freeRTOS_credel_Task”的Cube文件中进行修改:
1. 再额外配置两个KEY的GPIO:
由原理图可知:按钮1按下对应PA0变低,按钮2按下对应PA1变低:
2. 再额外增加两个任务:
Keil
在freertos.c中:
#include "stdio.h"
/* USER CODE END Header_StartTaskLED_1 */
void StartTaskLED_1(void const * argument)
{
/* USER CODE BEGIN StartTaskLED_1 */
/* Infinite loop */
for(;;) //相当于一个while(1)
{
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_8);//翻转LED1的状态
osDelay(500); //一个Cube封装的Delay函数,毫秒为单位
}
/* USER CODE END StartTaskLED_1 */
}
/* USER CODE BEGIN Header_StartTaskLED_2 */
/**
* @brief Function implementing the TaskLED_2 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTaskLED_2 */
void StartTaskLED_2(void const * argument)
{
/* USER CODE BEGIN StartTaskLED_2 */
/* Infinite loop */
for(;;)
{
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_9);//翻转LED2的状态
osDelay(1000);
}
/* USER CODE END StartTaskLED_2 */
}
/* USER CODE BEGIN Header_StartTaskKEY_1 */
/**
* @brief Function implementing the TaskKEY_1 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTaskKEY_1 */
void StartTaskKEY_1(void const * argument)
{
/* USER CODE BEGIN StartTaskKEY_1 */
/* Infinite loop */
for(;;)
{
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET){
osDelay(20);
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET){ //按键消抖
printf("KEY1 has been pressed\r\n");
if(TaskLED_1Handle != NULL){ //判断LED1任务是否存在,此处是NULL而不是pdPASS还是因为Cube自己的封装
//如果任务存在
printf("LED1_task detected\r\n");
osThreadTerminate(TaskLED_1Handle); //则删除LED1任务,此处的osThreadTerminate也是Cube封装了vTaskDelete的函数
TaskLED_1Handle = NULL;//这句不能忘
if(TaskLED_1Handle == NULL){
printf("LED1_task has been deleted\r\n");
}
}else{
//如果任务不存在
printf("LED1_task not detected\r\n");
osThreadDef(TaskLED_1, StartTaskLED_1, osPriorityNormal, 0, 128);
TaskLED_1Handle = osThreadCreate(osThread(TaskLED_1), NULL);//则创建LED1任务,这两句话就照抄上面创建任务的语句就可以
if(TaskLED_1Handle != NULL){
printf("LED1_task has been created\r\n");
}
}
}
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET); //等待按键松开,防止出现按钮一直按着,就一直删除创建任务
}
osDelay(10);
}
/* USER CODE END StartTaskKEY_1 */
}
/* USER CODE BEGIN Header_StartTaskKEY_2 */
/**
* @brief Function implementing the TaskKEY_2 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTaskKEY_2 */
void StartTaskKEY_2(void const * argument)
{
/* USER CODE BEGIN StartTaskKEY_2 */
static int flag = 0; //每次创建
/* Infinite loop */
for(;;)
{
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET){
osDelay(20);
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET){ //按键消抖
printf("KEY2 has been pressed\r\n");
if(flag == 0){///判断LED2任务是否是运行态
//如果是运行态
printf("LED2_task is now running\r\n");
osThreadSuspend(TaskLED_2Handle);//将LED2任务挂起,使其进入挂起态,osThreadSuspend也是Cube对vTaskSuspend()函数的封装
printf("LED2_task has been suspended\r\n");
flag = 1; //flag为1表示任务被挂起
}else{
//如果是挂起态
printf("LED2_task is now suspended\r\n");
osThreadResume(TaskLED_2Handle);//将LED2任务恢复,使其进重新进入运行态,osThreadResume也是Cube对xTaskResume()函数的封装
printf("LED2_task has been resumed\r\n");
flag = 0; //flag为1表示任务正在运行
}
}
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET); //等待按键松开,防止出现按钮一直按着,就一直挂起恢复任务
}
osDelay(10);
}
/* USER CODE END StartTaskKEY_2 */
}
实现效果
1. 首先可以看到LED1和LED2和上上节一样以不同的频率同时闪烁
2. 打开串口助手,并按下KEY1:
此时LED1任务被删除,只有黄色的LED2灯在闪烁
3. 再按一下KEY1:
此时LED1任务被重新创建,两盏LED灯又开始一起不同频率闪烁
4. 按一下KEY2:
此时LED2任务被挂起,蓝色的LED1灯在闪烁,而黄色的LED2灯会保持在按键按下时的状态
5. 再按一下KEY2:
此时LED2任务恢复运行,两盏LED灯又开始一起不同频率闪烁