STM32CubeMX学习笔记(32)——FreeRTOS实时操作系统使用(事件)

一、FreeRTOS简介

FreeRTOS 是一个可裁剪、可剥夺型的多任务内核,而且没有任务数限制。FreeRTOS 提供了实时操作系统所需的所有功能,包括资源管理、同步、任务通信等。

FreeRTOS 是用 C 和汇编来写的,其中绝大部分都是用 C 语言编写的,只有极少数的与处理器密切相关的部分代码才是用汇编写的,FreeRTOS 结构简洁,可读性很强!最主要的是非常适合初次接触嵌入式实时操作系统学生、嵌入式系统开发人员和爱好者学习。

最新版本 V9.0.0(2016年),尽管现在 FreeRTOS 的版本已经更新到 V10.4.1 了,但是我们还是选择 V9.0.0,因为内核很稳定,并且 上资料很多,因为 V10.0.0 版本之后是亚马逊收购了FreeRTOS之后才出来的版本,主要添加了一些云端组件,一般采用 V9.0.0 版本足以。

  • FreeRTOS官 :http://www.freertos.org/
  • 代码托管 站:https://sourceforge.net/projects/freertos/files/FreeRTOS/

二、新建工程

1. 打开 STM32CubeMX 软件,点击“新建工程”

3. 配置时钟
RCC 设置,选择 HSE(外部高速时钟) 为 Crystal/Ceramic Resonator(晶振/陶瓷谐振器)

4. 配置调试模式
非常重要的一步,否则会造成第一次烧录程序后续无法识别调试器
SYS 设置,选择 Debug 为 Serial Wire

在基于STM32 HAL的项目中,一般需要维护的 “时基” 主要有2个:

  1. HAL的时基,SYS Timebase Source
  2. OS的时基(仅在使用OS的情况下才考虑)

而这些 “时基” 该去如何维护,主要分为两种情况考虑:

  • 裸机运行
    可以通过 (滴答定时器)或 ()定时器 的方式来维护 ,也就是HAL库中的 ,这是HAL库中维护的一个全局变量。在裸机运行的情况下,我们一般选择默认的 (滴答定时器) 方式即可,也就是直接放在 中断服务函数中来维护。

  • 带OS运行
    前面提到的 是STM32的HAL库中的新增部分,主要用于实现 以及作为各种 timeout 的时钟基准。

    在使用了OS(操作系统)之后,OS的运行也需要一个时钟基准(简称“时基”),来对任务和时间等进行管理。而OS的这个 时基 一般也都是通过 (滴答定时器) 来维护的,这时就需要考虑 “HAL的时基” 和 “OS的时基” 是否要共用 (滴答定时器) 了。

    如果共用SysTick,当我们在CubeMX中选择启用FreeRTOS之后,在生成代码时,CubeMX一定会 如下提示:

    • Event flags Name: 事件组名称
    • Allocation: 分配方式: 动态内存创建
    • Conrol Block Name: 控制块名称

    4.3 创建任务Task

    我们创建两个任务,一个触发事件任务,一个等待事件任务。

    • Task Name: 任务名称
    • Priority: 优先级,在 FreeRTOS 中,数值越大优先级越高,0 代表最低优先级
    • Stack Size (Words): 堆栈大小,单位为字,在32位处理器(STM32),一个字等于4字节,如果传入512那么任务大小为512*4字节
    • Entry Function: 入口函数
    • Code Generation Option: 代码生成选项
    • Parameter: 任务入口函数形参,不用的时候配置为0或NULL即可
    • Allocation: 分配方式: 动态内存创建
    • Buffer Name: 缓冲区名称
    • Conrol Block Name: 控制块名称

    五、KEY

    5.1 参数配置

    在 中选择 设置。

    六、UART串口打印

    查看 STM32CubeMX学习笔记(6)——USART串口使用

    七、生成代码

    输入项目名和项目路径

    八、互斥量

    8.1 基本概念

    事件是一种实现任务间通信的机制,主要用于实现多任务间的同步,但事件通信只能是事件类型的通信,无数据传输。 与信 量不同的是,它可以实现一对多,多对多的同步。即一个任务可以等待多个事件的发生:可以是任意一个事件发生时唤醒任务进行事件处理;也可以是几个事件都发生后才唤醒任务进行事件处理。同样,也可以是多个任务同步多个事件。

    每一个事件组只需要很少的 RAM 空间来保存事件组的状态。事件组存储在一个 EventBits_t 类型的变量中,该变量在事件组结构体中定义 。在 STM32 中 , 我们一般 configUSE_16_BIT_TICKS 定义为 0,那么 uxEventBits 是 32 位的,有 24 个位用来实现事 件标志组。每一位代表一个事件,任务通过“逻辑与”或“逻辑或”与一个或多个事件建立关联,形成一个事件组。 事件的“逻辑或”也被称作是独立型同步,指的是任务感兴趣的所有事件任一件发生即可被唤醒;事件“逻辑与”则被称为是关联型同步,指的是任务感兴趣的若干事件都发生时才被唤醒,并且事件发生的时间可以不同步。

    多任务环境下,任务、中断之间往往需要同步操作,一个事件发生会告知等待中的任务,即形成一个任务与任务、中断与任务间的同步。 事件可以提供一对多、多对多的同步操作。一对多同步模型:一个任务等待多个事件的触发,这种情况是比较常见的;多对多同步模型:多个任务等待多个事件的触发。
    任务可以通过设置事件位来实现事件的触发和等待操作。FreeRTOS 的事件仅用于同步,不提供数据传输功能。

    FreeRTOS 提供的事件具有如下特点:

    • 事件只与任务相关联,事件相互独立,一个 32 位的事件集合(EventBits_t 类型的变量,实际可用与表示事件的只有 24 位),用于标识该任务发生的事件类型,其中每一位表示一种事件类型(0 表示该事件类型未发生、1 表示该事件类型已经发生),一共 24 种事件类型。
    • 事件仅用于同步,不提供数据传输功能。
    • 事件无排队性,即多次向任务设置同一事件(如果任务还未来得及读走),等效于只设置一次。
    • 允许多个任务对同一事件进行读写操作。
    • 支持事件等待超时机制。

    在 FreeRTOS 事件中,每个事件获取的时候,用户可以选择感兴趣的事件,并且选择读取事件信息标记,它有三个属性,分别是逻辑与,逻辑或以及是否清除标记。当任务等待事件同步时,可以通过任务感兴趣的事件位和事件信息标记来判断当前接收的事件是否满足要求,如果满足则说明任务等待到对应的事件,系统将唤醒等待的任务;否则,任务会根据用户指定的阻塞超时时间继续等待下去。

    8.2 运作机制

    任务 1 对事件 3 或事件 5 感兴趣(逻辑或),当发生其中的某一个事件都会被唤醒,并且执行相应操作。而任务 2 对事件 3 与事件 5 感兴趣(逻辑与),当且仅当事件 3 与事件 5 都发生的时候,任务 2 才会被唤醒,如果只有一个其中一个事件发生,那么任务还是会继续等待事件发生。如果接在收事件函数中设置了清除事件位 xClearOnExit,那么当任务唤醒后将把事件 3 和事件 5 的事件标志清零,否则事件标志将依然存在。

    九、相关API说明

    9.1 osEventFlagsNew

    用于创建一个事件组,并返回对应的ID。

    函数 osEventFlagsId_t osEventFlagsNew (const osEventFlagsAttr_t *attr)
    参数 attr: 引用由osEventFlagsAttr_t定义的事件属性
    返回值 成功返回事件组ID,失败返回0

    9.2 osEventFlagsDelete

    当系统不再使用事件对象时,可以通过删除事件对象控制块来释放系统资源。

    函数 osStatus_t osEventFlagsDelete (osEventFlagsId_t ef_id)
    参数 ef_id: 事件组ID
    返回值 错误码

    9.3 osEventFlagsSet

    用于置位事件组中指定的位,当位被置位之后,阻塞在该位上的任务将会被解锁。使用该函数接口时,通过参数指定的事件标志来设定事件的标志位,然后遍历等待在事件对象上的事件等待列表,判断是否有任务的事件激活要求与当前事件对象标志值匹配,如果有,则唤醒该任务。简单来说,就是设置我们自己定义的事件标志位为 1,并且看看有没有任务在等待这个事件,有的话就唤醒它。该函数可以在中断中使用。

    函数 uint32_t osEventFlagsSet (osEventFlagsId_t ef_id, uint32_t flags)
    参数 ef_id: 事件组ID

    flags: 指定事件中的事件标志位。如设置 uxBitsToSet 为 0x08 则只置位位 3,如果设置 uxBitsToSet 为 0x09 则位 3 和位 0 都需要被置位

    返回值 返回调用 osEventFlagsSet() 时事件组中的值

    要想在中断中使用该函数必须在 中把 选择 来使能。

    STM32CubeMX学习笔记(32)——FreeRTOS实时操作系统使用(事件)

    9.4 osEventFlagsWait

    用于获取事件组中的一个或多个事件发生标志,当要读取的事件标志位没有被置位时任务将进入阻塞等待状态。

    函数 uint32_t osEventFlagsWait (osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout)
    参数 ef_id: 事件组ID

    flags: 指定事件中的事件标志位。如设置 uxBitsToSet 为 0x08 则只置位位 3,如果设置 uxBitsToSet 为 0x09 则位 3 和位 0 都需要被置位

    **options:osFlagsNoClear是否清除flags指定的事件标志位,osFlagsWaitAll是否 等待flags指定的位都置位的时候才满足任务唤醒的条件

    **timeout:最大超时时间,单位为系统节拍周期,常量 portTICK_PERIOD_MS 用于辅助把时间转换成 MS

    返回值 返回事件中的哪些事件标志位被置位,返回值很可能并不是用户指定的事件位,需要对返回值进行判断再处理

    9.5 osEventFlagsClear

    用于清除事件组指定的位,如果在获取事件的时候没有将对应的标志位清除,那么就需要用这个函数来进行显式清除。该函数可以在中断中使用。

    函数 uint32_t osEventFlagsClear (osEventFlagsId_t ef_id, uint32_t flags)
    参数 ef_id: 事件组ID

    flags: 指定事件组中的哪个位需要清除。如设置 uxBitsToSet 为 0x08 则只清除位 3,如果设置 uxBitsToSet 为 0x09 则位 3 和位 0 都需要被清除

    返回值 事件在还没有清除指定位之前的值

    十、示例

    10.1 任务式

    声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2022年3月4日
下一篇 2022年3月4日

相关推荐