STM32CubeMX学习笔记(29)——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 软件,点击“新建工程”

STM32CubeMX学习笔记(29)——FreeRTOS实时操作系统使用(消息队列)

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

STM32CubeMX学习笔记(29)——FreeRTOS实时操作系统使用(消息队列)

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

STM32CubeMX学习笔记(29)——FreeRTOS实时操作系统使用(消息队列)

在基于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一定会报如下提示:

    STM32CubeMX学习笔记(29)——FreeRTOS实时操作系统使用(消息队列)

    STM32CubeMX学习笔记(29)——FreeRTOS实时操作系统使用(消息队列)
    • Queue Name: 队列名称
    • Queue Size: 队列能够存储的最大单元数目,即队列深度
    • Queue Size: 队列中数据单元的长度,以字节为单位
    • Allocation: 分配方式: 动态内存创建
    • Buffer Name: 缓冲区名称
    • Buffer Size: 缓冲区大小
    • Conrol Block Name: 控制块名称

    4.3 创建任务Task

    我们创建两个任务,一个消息接收任务,一个消息发送任务。

    STM32CubeMX学习笔记(29)——FreeRTOS实时操作系统使用(消息队列)
    • 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 参数配置

    在 中选择 设置。

    STM32CubeMX学习笔记(29)——FreeRTOS实时操作系统使用(消息队列)

    六、UART串口打印

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

    七、生成代码

    输入项目名和项目路径

    STM32CubeMX学习笔记(29)——FreeRTOS实时操作系统使用(消息队列)
    每个外设生成独立的 文件
    不勾:所有初始化代码都生成在 main.c
    勾选:初始化代码生成在对应的外设文件。 如 GPIO 初始化代码生成在 gpio.c 中。
    STM32CubeMX学习笔记(29)——FreeRTOS实时操作系统使用(消息队列)

    八、创建队列

    8.1 相关API说明

    8.1.1 osMessageQId

    队列ID。例如,对的调用返回。可用作参数到以删除队列。

    8.1.2 osMessageCreate

    使用动态内存的方式创建一个新的队列。

    函数 osMessageQId osMessageCreate (const osMessageQDef_t *queue_def, osThreadId thread_id)
    参数 queue_def: 引用由osMessageQDef定义的队列

    thread_id: 线程ID或NULL

    返回值 成功返回任务ID,失败返回0

    8.1.3 osMessageDelete

    队列删除函数是根据消息队列ID直接删除的,删除之后这个消息队列的所有信息都会被系统回收清空,而且不能再次使用这个消息队列了。

    函数 osStatus osMessageDelete (osMessageQId queue_id)
    参数 queue_id: 消息队列ID,表示的是要删除哪个想队列
    返回值 错误码

    8.2 示例

    九、消息发送与接收

    9.1 相关API说明

    9.1.1 osMessagePut

    用于向队列尾部发送一个队列消息。消息以拷贝的形式入队,而不是以引用的形式。可用在中断服务程序中。

    函数 osStatus osMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec)
    参数 queue_id: 目标队列ID。这个句柄即是调用 osMessageCreate() 创建该队列时的返回值

    info: 发送数据的指针。其指向将要复制到目标队列中的数据单元。由于在创建队列时设置了队列中数据单元的长度,所以会从该指针指向的空间复制对应长度的数据到队列的存储区域。

    millisec: 队列空时,阻塞超时的最大时间。如果该参数设置为 0,函数立刻返回。超时时间的单位为系统节拍周期,常量 portTICK_PERIOD_MS 用于辅助计算真实的时间,单位为 ms。如果 INCLUDE_vTaskSuspend 设置成 1,并且指定延时为 portMAX_DELAY 将导致任务无限阻塞(没有超时)。

    返回值 错误码

    9.1.2 osMessageGet

    用于从一个队列中接收消息并把消息从队列中删除。接收的消息是以拷贝的形式进行的,所以我们必须提供一个足够大空间的缓冲区。具体能够拷贝多少数据到缓冲区,这个在队列创建的时候已经设定。可用在中断服务程序中。

    函数 osEvent osMessageGet (osMessageQId queue_id, uint32_t millisec)
    参数 queue_id: 被读队列ID。这个句柄即是调用 osMessageCreate() 创建该队列时的返回值

    millisec: 队列空时,阻塞超时的最大时间。如果该参数设置为 0,函数立刻返回。超时时间的单位为系统节拍周期,常量 portTICK_PERIOD_MS 用于辅助计算真实的时间,单位为 ms。如果 INCLUDE_vTaskSuspend 设置成 1,并且指定延时为 portMAX_DELAY 将导致任务无限阻塞(没有超时)。

    返回值 错误码

    9.1.3 osMessagePeek

    osMessagePeek() 也是从从队列中接收数据单元,不同的是并不从队列中删出接收到的单元。osMessagePeek() 从队列首接收到数据后,不会修改队列中的数据,也不会改变数据在队列中的存储序顺。可用在中断服务程序中。

    函数 osEvent osMessagePeek (osMessageQId queue_id, uint32_t millisec)
    参数 queue_id: 被读队列ID。这个句柄即是调用 osMessageCreate() 创建该队列时的返回值

    millisec: 队列空时,阻塞超时的最大时间。如果该参数设置为 0,函数立刻返回。超时时间的单位为系统节拍周期,常量 portTICK_PERIOD_MS 用于辅助计算真实的时间,单位为 ms。如果 INCLUDE_vTaskSuspend 设置成 1,并且指定延时为 portMAX_DELAY 将导致任务无限阻塞(没有超时)。

    返回值 错误码

    9.2 示例

    9.2.1 阻塞式发送与接收

    来源:Leung_ManWah

    声明:本站部分文章及图片转载于互联网,内容版权归原作者所有,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

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

相关推荐