嵌入式实时操作系统RTOS_使用CubeMX进行FreeRTOS的任务创建_软件定时器的使用

FreeRTOS简介

CMSIS-RTOS v2

  • 在CubeMX软件的中间件已经集成了FreeRTOS,可以自动生成FreeRTOS的程序框架,省去了移植RTOS的步骤,因此以FreeRTOS为例来讲解RTOS的具体使用
  • 此外,我们并不使用FreeRTOS原有的接口函数,而是使用经过封装的函数,这一封装称为CMSIS-RTOS v2,这是一套由ARM提出,针对Cortex-M处理器的RTOS软件接口标准,使得跨操作系统的调用与移植更加方便

FreeRTOS的初始化配置

  • 启用FreeRTOS

    使用CubeMX配置使用FreeRTOS步骤如下:

    1. 在Pinout & configuration 页面的左侧栏中展开Middleware and Software Pack,勾选FREERTOS,进入FreeRTOS的配置页面
    2. 在Mode栏中选择Interface 为CMSIS-V2
    3. 在Configuration 栏的config parameters 标签页配置RTOS的基本属性

    注意:由于新版本的keil将编译器升级为了AC6,因此要进行如下操作让编译正常:

    C:\Users\你的用户名\STM32Cube\Repository\你要设置的单片机型号\Middlewares\Third_Party\FreeRTOS\Source\portable\GCC\ARM_CM4F中的两个文件port.cportmacro.h复制到C:\Users\你的用户名\STM32Cube\Repository\你要设置的单片机型号\Middlewares\Third_Party\FreeRTOS\Source\portable\RVDS\ARM_CM4F中替换原来的文件

    如果安装路径不一样找不到Repository文件夹,可以在CubeMX中在Help菜单栏中打开Connection&Updates来看Repository文件夹路径

  • FreeRTOS的属性
    • USE_PREEMPTION:是否启用抢占式调度,默认支持

    • TICK_RATE_HZ:定义系统节拍数,默认为1000Hz,即1ms

    • MAX_PRIORTIES:定义可供用户使用的最大优先级数,默认为56,即0~55可用,数字越大优先级越高(与中断优先级编号越小越高相反)

    • MINIMAL_STACK_SIZE:任务栈的大小,默认为512B

    • TOTAL_HEAP_SIZE:堆空间的大小,默认为15360字节,用于创建任务、信号量、消息队列以及软件计数器的使用;

      任务的创建、任务栈的分配、各种系统服务的创建都需要从堆空间分配内存,如果用户创建了较多的任务或系统服务或者定义了较多的局部变量,可以根据实际情况增加该值

    • TIMER_TASK_PRIORITY:设置软件定时器的优先级,默认为2

  • 时钟节拍

    时钟节拍是一个周期性的定时中断,也即前文介绍的SysTick,是延时、超时、时间片流转的基本单位,如延时函数的功能便是将任务延时若干整数倍的时钟节拍

    需要注意的是,前文介绍的SysTick已被用作HAL库的时间基准,为了避免HAL库与RTOS相冲突,需要修改HAL库的时间基准为其他定时器,把SysTick留给RTOS

    修改方法如下:

    1. 在Pinout & configuration 页面的左侧栏中展开System Core,选择SYS

    2. 将Timebase Source从Systick修改为某个TIM,如TIM10

    3. 为设定的定时器编写实现HAL库时间基准的中断回调函数

      void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
      {
      	if(htim->Instance==TIM10)//使用TIM10产生时间基准
      	{
      		HAL_IncTick();
      	}
      }
      

任务管理的接口函数

  • 任务创建函数osThreadNew

    用于创建一个新任务

  • 任务优先级设置函数osThreadSetPriority

    设置任务的优先级,在CMSIS-RTOS2的封装中将56个优先级分为六大类:

    • osPriorityIdle:最低优先级,为空闲任务保留,对应1
    • osPriorityLowN,低优先级;osPriorityBelowNormalN,低于正常优先级;osPriorityNormalN,正常优先级;osPriorityAboveNormalN,高于正常优先级;osPriorityHighN,高优先级,以上分类各含8个优先级编号
    • osPriorityRealtimeN,实时优先级,对应48-55
    • osPriorityISR,最高优先级,为ISR延迟任务,即由中断触发的任务保留,不能用于用户的任务,对应56
  • 以上两个函数都可由CubeMX自动生成,在接下来任务创建一节中介绍如何配置

  • 延时函数osDelay

    调用了延时函数的任务将进入阻塞态,并立即进行任务调度,经过指定的时间节拍后,任务会自动返回就绪态

    该函数不能在中断服务程序中使用

任务创建

任务创建的初始化配置

  • 使用CubeMX来创建任务
    1. 在FreeRTOS的配置窗口中,选择Task and Queues 标签页,进行任务的创建(默认已经创建了一个defaultTask)
    2. 点击Add按钮创建新任务
    3. 双击创建的任务,弹出Edit Task,可对任务名、任务函数Entry Function、优先级、任务栈大小进行修改
  • 系统内存使用情况

    在完成了所有的任务和系统服务的配置后,系统内存的最终使用情况可在FreeRTOS Heap Usage标签页中看到

    • HEAP STILL AVAILABLE 表示可用的堆空间大小
    • TOTAL HEAP USED 表示已经使用的堆空间大小
    • 其余各行是各个系统服务所占用的堆空间大小,可根据使用情况修改TOTAL_HEAP_SIZE

任务创建的代码实现

  • 任务创建的主程序

    以下内容由CubeMX自动生成

    #include "main.h"
    #include "cmsis_os.h"//使用CMSIS-RTOS2封装后接口函数的头文件
    int main()
    {
    	osKernelInitialize();//初始化RTOS内核
    	MX_FREERTOS_Init();//此函数中包含了创建任务的函数
    	{
    		 defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
    		//在CubeMX中创建任务后,自动生成这个任务的句柄以及属性结构体
    	}
    	osKernelStart();//启动内核,开始任务调度
    	//启动内核后while(1)中的代码将不会执行
    }
    
  • 任务函数
    void StartDefaultTask(void *argument)
    {
      /* USER CODE BEGIN StartDefaultTask */
      /* Infinite loop */
      for(;;)
      {
    	//此处为任务代码
        osDelay(1);
      }
      /* USER CODE END StartDefaultTask */
    }
    

软件定时器

软件定时器概述

  • 硬件与软件定时器

    某个任务周期性地/延时确定时间执行是常用的功能需求,我们往往需要定时器来实现这一点,而我们之前介绍的硬件定时器虽然精确,但有数量有限,不同硬件操作代码不同不便于移植的问题

  • 而软件定时器基于系统节拍,模拟硬件的功能,具备一定的通用性,数量也不受限制,FreeRTOS中提供了软件定时器的功能,经CMSIS-RTOS v2 封装有后文介绍的接口函数

  • 软件定时器的分类
    • 单次触发osTimerOnce:执行一次回调函数后不再运行

    • 周期触发osTimerPeriodic:重复执行回调函数,直到用户停止或删除该定时器

软件定时器的接口函数

  • 软件定时器创建函数osTimerNew

    创建一个单次触发osTimerOnce或周期触发osTimerPeriodic的软件定时器,并将其与回调函数相连,创建后的定时器处于停止状态

    不能从中断服务程序中调用

    osTimerId_t osTimerNew(osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr)
    //func:指向回调函数的函数指针
    //type:osTimerOnce表示单次触发定时器, osTimerPeriodic表示周期触发定时器
    //argument:回调函数的入口参数
    //attr:定时器属性的指针,默认值为NULL
    //返回值为定时器的句柄,用于标识软件定时器
    
  • 软件定时器启动函数osTimerStart

    不能从中断服务程序中调用

    osStatus_t osTimerStart(osTimerId_t timer_id, uint32_t ticks)
    //timer_id:要启动的软件定时器
    //ticks:对单次触发的定时器表示延时,对周期触发的定时器表示周期
    //具体数值根据系统节拍与需求决定
    
  • 软件定时器停止函数

    不能从中断服务程序中调用

    osStatus_t osTimerStop(osTimerId_t timer_id)
    

软件定时器的代码实现

  • 创建两个软件定时器,一个每隔1s触发一次,另一个用于控制指示灯在系统启动5s后再开启

    //创建并启动软件定时器,写在main里
    osTimerId_t ComTimeHandle;
    osTimerId_t LEDTimeHandle;
    ComTimeHandle = osTimerNew(ComCallback, osTimerPeriodic, NULL, NULL);
    LEDTimeHandle = osTimerNew(LEDCallback, osTimerOnce, NULL, NULL);
    osTimerStart(ComCallback,1000);
    osTimerStart(LEDCallback,5000);
    
  • 还要写回调函数

    void ComCallback(void *argument)
    {
    	//每隔1s触发一次
    }
    
    void LEDCallback(void *argument)
    {
    	//只触发一次
    }
    
posted @ 2025-12-29 12:38  无术师  阅读(344)  评论(0)    收藏  举报