FreeRTOS学习(一)

前言

最近正在学习和FreeRTOS相关的知识,在此记录一下,学习资料来自正点原子
在学习之前,我也有一个和很多初学者共同的疑惑----Why RTOS?
在探究这个问题之前,我想先回顾一下什么是RTOS

RTOS介绍

RTOS即为Real Time Operating System(实时操作系统)在以往的裸机编程中我们会通过定时器中断结合while循环来控制单片机

这样造成的现象就是不能多个任务同时进行,必须要执行完上一个任务才能执行下一个,可能有些朋友会想:靠定时器中断回调就可以了啊,但是中断是不能执行长时间的任务的,稍有帮助的一种思路就是在中断回调函数中挂起对应的工作标志位,while中检测到后就会开始执行,但这样还是会浪费很多时间在等待上一个任务中

这个时候RTOS的优势就展现出来了

RTOS可以控制CPU不断地工作,充分利用CPU的所有性能,简单来说就是给每个任务分片对应的运行时间,时间到了就进入下一个任务,上一个任务的节点会通过堆栈指针保留起来,等下次轮到它的时候会从上一次开始执行,Unix系统也是如此,而笔者选用FreeRTOS的原因是因为其免费且是ST官方钦定的RTOS,可以在CUBEMX中一键配置(不得不感叹大厂才做环境啊)

相关原理

这次我只打算讨论动态任务的创建和删除,这里简单带过一下原理

任务调度

FreeRTOS支持三种任务调度方式:抢占式调度、时间片调度以及协程式调度,我们前面提到了RTOS中的任务是可以连续执行的,每个任务有对应的工作周期,这里就重点介绍一下抢占式和时间片调度

抢占式调度

抢占式调度针对的是优先级不同的任务,每个任务都被分配了一个优先级,优先级高的可以抢占优先级低的任务

这里的优先级和中断机制类似,FreeRTOS的工作方式有两种:特殊方法&通用方法,在通用方法下的优先级算法是通过软件配置,理论上可以有很多个,相反的特殊方法则是基于32位MCU硬件,对应的优先级数有0~31,两者的区别是后者的运行速度高于前者,数值越大的优先级越大,这是和中断机制不同的,还需要注意的一点是:中断的优先级比RTOS中的任何任务都要高

时间片调度

和上面不同,时间片调度针对的是同一个优先级下的任务

当多个任务的优先级相同时,任务调度器会在每一次系统时钟节拍到(1MS)的时候切换任务

任务状态

FreeRTOS中的任务有四种状态:运行态、就绪态、阻塞态、挂起态
并且除了运行态其他三种状态都有自身对应的任务状态列表:就绪列表、阻塞列表、挂起列表

在一个线程中只能有一个任务处于运行态,其他的任务会处于另外的三种状态,如下图所示

只有就绪态可以和运行态相互转换,运行态可以进入任意一种其他形态,换句话说就是所有的任务要先从挂起态&阻塞态进入就绪态才可以顺利开始线程

在这里插入图片描述

抢占式流程

具体的抢占式流程可以看这张图
在这里插入图片描述

这里的优先级顺序为Task3>Task2>Task1,因此可以看出当Task1处在运行态且Task2处在阻塞&挂起态时Task1可以正常工作,但当Task2处在就绪态后Task1会被优先级高的Task2抢占,此时堆栈会记录Task1的工作进度并等到下一次Task2&Task3均被阻塞&挂起时再重新执行完剩下的工作

时间片流程

若创建的三个任务Task1、Task2、Task3均为同一个优先级,这就代表它们处在就绪列表的同一个位置处,此时会按照分配的顺序从Task1执行1ms->Task2执行1ms->Task3执行1ms->Task1执行1ms往复工作

工程搭建

接下来就可以进入CUBEMX配置了,我所使用的开发板是正点的基于F103ZET6的精英板
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传在这里插入图片描述

一些简单的配置就不多介绍了
下面我们来看FreeRTOS的配置
关于其他的配置可以参考正点的资料或者查看别的文章,有很多详细的介绍,这里就只介绍最简单的创建一个任务

在这里插入图片描述

接下来就可以学习相关的代码了,下面这些代码是FreeRTOSConfig.h中的,关于各种宏的说明我已加上了中文注释,可自行阅读

配置代码

/* USER CODE BEGIN Header */  
/*  
 * FreeRTOS Kernel V10.0.1 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * http://www.FreeRTOS.org * http://aws.amazon.com/freertos * * 1 tab == 4 spaces! *//* USER CODE END Header */  
  
#ifndef FREERTOS_CONFIG_H  
#define FREERTOS_CONFIG_H  
  
/*-----------------------------------------------------------  
 * Application specific definitions. * * These definitions should be adjusted for your particular hardware and * application requirements. * * These parameters and more are described within the 'configuration' section of the * FreeRTOS API documentation available on the FreeRTOS.org web site. * * See http://www.freertos.org/a00110.html *----------------------------------------------------------*/  
/* USER CODE BEGIN Includes */  
/* Section where include file can be added */  
/* USER CODE END Includes */  
  
/* Ensure definitions are only used by the compiler, and not by the assembler. */  
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)  
  #include <stdint.h>  
  extern uint32_t SystemCoreClock;  
#endif  
#define configUSE_PREEMPTION                     1  //抢占式调度  
#define configSUPPORT_STATIC_ALLOCATION          0  //采用静态方式管理内存  
#define configSUPPORT_DYNAMIC_ALLOCATION         1  //采用动态方式管理内存  
#define configUSE_IDLE_HOOK                      0  //使能使用空闲任务钩子函数  
#define configUSE_TICK_HOOK                      0  //使能使用系统时钟中断节拍钩子函数  
#define configCPU_CLOCK_HZ                       ( SystemCoreClock )  //将CPU内核时钟设置为SYSTICK  
#define configTICK_RATE_HZ                       ((TickType_t)1000) //设置RTOS节拍中断频率  
#define configMAX_PRIORITIES                     ( 32 ) //设置任务的最大优先级数  
#define configMINIMAL_STACK_SIZE                 ((uint16_t)128)  //设置空闲任务的栈空间大小  
#define configTOTAL_HEAP_SIZE                    ((size_t)3072) //设置系统的动态内存大小,即为内存堆(Byte)  
#define configMAX_TASK_NAME_LEN                  ( 16 ) //设置任务名的最大字符数  
#define configUSE_TRACE_FACILITY                 1  //用于使能可视化的跟踪调试  
#define configUSE_16_BIT_TICKS                   0  //定义系统节拍计数器的数据类型,此时代表为uint32_t,反之为uint16_t  
#define configUSE_MUTEXES                        1  //用于使能互斥信号量  
#define configQUEUE_REGISTRY_SIZE                8  //用于定义可以注册的队列和信号量的最大数量  
#define configUSE_RECURSIVE_MUTEXES              1  //用于使能递归互斥信号量  
#define configUSE_COUNTING_SEMAPHORES            1  //用于使能计数型信号量  
#define configUSE_PORT_OPTIMISED_TASK_SELECTION  1  //选择下一个要执行的任务(通用方法&特殊方法)  
  
/* Co-routine definitions. */  
#define configUSE_CO_ROUTINES                    0  //用于启用协程模式  
#define configMAX_CO_ROUTINE_PRIORITIES          ( 2 )  //设置协程时的最大任务优先级数量  
  
/* Software timer definitions. */  
#define configUSE_TIMERS                         1  //启动软件定时器功能  
#define configTIMER_TASK_PRIORITY                ( 2 )  //设置软件定时器处理任务的优先级  
#define configTIMER_QUEUE_LENGTH                 10 //定义软件定时器队列的长度  
#define configTIMER_TASK_STACK_DEPTH             256  //设置软件定时器处理任务的栈空间大小  
  
/* Set the following definitions to 1 to include the API function, or zero  
to exclude the API function. */  
#define INCLUDE_vTaskPrioritySet            1 //设置任务优先级  
#define INCLUDE_uxTaskPriorityGet           1 //获取任务优先级  
#define INCLUDE_vTaskDelete                 1 //删除任务  
#define INCLUDE_vTaskCleanUpResources       0 //可以回收删除任务后的资源  
#define INCLUDE_vTaskSuspend                1 //挂起任务  
#define INCLUDE_vTaskDelayUntil             1 //任务绝对延时  
#define INCLUDE_vTaskDelay                  1 //任务延时  
#define INCLUDE_xTaskGetSchedulerState      1 //获取任务调度器状态  
#define INCLUDE_xTimerPendFunctionCall      1 //将函数的执行挂到定时器服务任务  
#define INCLUDE_xQueueGetMutexHolder        1 //查看队列中的互斥信号量  
#define INCLUDE_uxTaskGetStackHighWaterMark 1 //获取任务堆栈历史剩余最小值  
#define INCLUDE_eTaskGetState               1 //获取任务状态  
  
/*  
 * The CMSIS-RTOS V2 FreeRTOS wrapper is dependent on the heap implementation used * by the application thus the correct define need to be enabled below */#define USE_FreeRTOS_HEAP_4  
  
/* Cortex-M specific definitions. */  
#ifdef __NVIC_PRIO_BITS  
 /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */  
 #define configPRIO_BITS         __NVIC_PRIO_BITS#else  
 #define configPRIO_BITS         4  
#endif  
  
/* The lowest interrupt priority that can be used in a call to a "set priority"  
function. */  
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY   15  
  
/* The highest interrupt priority that can be used by any interrupt service  
routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL  
INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER  
PRIORITY THAN THIS! (higher priorities are lower numeric values. */  
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5  
  
/* Interrupt priorities used by the kernel port layer itself.  These are generic  
to all Cortex-M ports, and do not rely on any particular library functions. */  
#define configKERNEL_INTERRUPT_PRIORITY   ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )  
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!  
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */  
#define configMAX_SYSCALL_INTERRUPT_PRIORITY   ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )  
  
/* Normal assert() semantics without relying on the provision of an assert.h  
header file. */  
/* USER CODE BEGIN 1 */  
#define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); for( ;; );}  
/* USER CODE END 1 */  
  
/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS  
standard names. */  
#define vPortSVCHandler    SVC_Handler  
#define xPortPendSVHandler PendSV_Handler  
  
/* IMPORTANT: This define is commented when used with STM32Cube firmware, when the timebase source is SysTick,  
              to prevent overwriting SysTick_Handler defined within STM32Cube HAL */  
#define xPortSysTickHandler SysTick_Handler  
  
/* USER CODE BEGIN Defines */  
/* Section where parameter definitions can be added (for instance, to override default ones in FreeRTOS.h) */  
/* USER CODE END Defines */  
  
#endif /* FREERTOS_CONFIG_H */

点灯代码

/* USER CODE BEGIN Header */  
/**  
  ******************************************************************************  * File Name          : freertos.c  * Description        : Code for freertos applications  ******************************************************************************  * @attention  *  * <h2><center>&copy; Copyright (c) 2022 STMicroelectronics.  * All rights reserved.</center></h2>  *  * This software component is licensed by ST under Ultimate Liberty license  * SLA0044, the "License"; You may not use this file except in compliance with  * the License. You may obtain a copy of the License at:  *                             www.st.com/SLA0044  *  ******************************************************************************  *//* USER CODE END Header */  
  
/* Includes ------------------------------------------------------------------*/  
#include "FreeRTOS.h"  
#include "task.h"  
#include "main.h"  
#include "cmsis_os.h"  
  
/* Private includes ----------------------------------------------------------*/  
/* USER CODE BEGIN Includes */  
/* USER CODE END Includes */  
  
/* Private typedef -----------------------------------------------------------*/  
/* USER CODE BEGIN PTD */  
  
/* USER CODE END PTD */  
  
/* Private define ------------------------------------------------------------*/  
/* USER CODE BEGIN PD */  
#define LED1_ON() HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,GPIO_PIN_RESET)  
#define LED2_ON() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_RESET)  
#define LED1_OFF() HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,GPIO_PIN_SET)  
#define LED2_OFF() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_SET)  
/* USER CODE END PD */  
  
/* Private macro -------------------------------------------------------------*/  
/* USER CODE BEGIN PM */  
/* USER CODE END PM */  
  
/* Private variables ---------------------------------------------------------*/  
/* USER CODE BEGIN Variables */  
/* USER CODE END Variables */  
/* Definitions for defaultTask */  
osThreadId_t defaultTaskHandle;  
const osThreadAttr_t defaultTask_attributes = {  
  .name = "defaultTask",  
  .priority = (osPriority_t) osPriorityLow1,  
  .stack_size = 128 * 4  
};  
/* Definitions for MYTASK01 */  
osThreadId_t MYTASK01Handle;  
const osThreadAttr_t MYTASK01_attributes = {  
  .name = "MYTASK01",  
  .priority = (osPriority_t) osPriorityLow1,  
  .stack_size = 128 * 4  
};  
  
/* Private function prototypes -----------------------------------------------*/  
/* USER CODE BEGIN FunctionPrototypes */  
  
/* USER CODE END FunctionPrototypes */  
  
void StartDefaultTask(void *argument);  
void myTask01(void *argument);  
  
void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */  
  
/**  
  * @brief  FreeRTOS initialization  * @param  None  * @retval None  */void MX_FREERTOS_Init(void) {  
  /* USER CODE BEGIN Init */  
  
  /* USER CODE END Init */  
  /* USER CODE BEGIN RTOS_MUTEX */  /* add mutexes, ... */  /* USER CODE END RTOS_MUTEX */  
  /* USER CODE BEGIN RTOS_SEMAPHORES */  /* add semaphores, ... */  /* USER CODE END RTOS_SEMAPHORES */  
  /* USER CODE BEGIN RTOS_TIMERS */  /* start timers, add new ones, ... */  /* USER CODE END RTOS_TIMERS */  
  /* USER CODE BEGIN RTOS_QUEUES */  /* add queues, ... */  /* USER CODE END RTOS_QUEUES */  
  /* Create the thread(s) */  /* creation of defaultTask */  defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);  
  
  /* creation of MYTASK01 */  
  MYTASK01Handle = osThreadNew(myTask01, NULL, &MYTASK01_attributes);  
  
  /* USER CODE BEGIN RTOS_THREADS */  
  /* add threads, ... */  /* USER CODE END RTOS_THREADS */  
  /* USER CODE BEGIN RTOS_EVENTS */  /* add events, ... */  /* USER CODE END RTOS_EVENTS */  
}  
  
/* USER CODE BEGIN Header_StartDefaultTask */  
/**  
  * @brief  Function implementing the defaultTask thread.  * @param  argument: Not used  * @retval None  *//* USER CODE END Header_StartDefaultTask */  
void StartDefaultTask(void *argument)  
{  
  /* USER CODE BEGIN StartDefaultTask */  
  /* Infinite loop */  for(;;)  
  {  
    osDelay(100); //阻塞100ms  
    if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_4) == GPIO_PIN_RESET)  
    {  
      vTaskDelete(&MYTASK01Handle);  
    }  
  }  
  /* USER CODE END StartDefaultTask */  
}  
  
/* USER CODE BEGIN Header_myTask01 */  
/**  
* @brief Function implementing the MYTASK01 thread.  
* @param argument: Not used  
* @retval None  
*/  
/* USER CODE END Header_myTask01 */  
void myTask01(void *argument)  
{  
  /* USER CODE BEGIN myTask01 */  
  /* Infinite loop */  for(;;)  
  {  
    LED1_ON();  
    vTaskDelay(500);  //任务延时500ms  
    LED1_OFF();  
    osDelay(520); //阻塞520ms  
  }  
  /* USER CODE END myTask01 */  
}  
  
/* Private application code --------------------------------------------------*/  
/* USER CODE BEGIN Application */  
/* USER CODE END Application */  
  
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值