【问题标题】:How do I keep code portable while using FreeRTOS如何在使用 FreeRTOS 时保持代码可移植性
【发布时间】:2012-10-24 09:43:11
【问题描述】:

我不知道如何在我的应用程序中使用 FreeRTOS。让我提出一个简单的场景。假设我有 main 和一个具有一些硬件特定代码的模块。该代码可以用于控制系统或传感器中的特定电机......具有定义角色的任何硬件。在 module.c 中,我有一个名为 ModuleNameTask 的函数。在main 中,我使用xTaskCreate 创建任务并通过ModuleNameTask。由于我的ModuleNameTask 是在module.c 而不是main.c 中定义的,我现在必须在module.c 中包含一些FreeRTOS 以便使用vTaskDelay 之类的功能。我不喜欢将这些文件包含在 module.c 中的事实,因为我觉得它不再可移植。

那么,我该如何处理呢?我应该从 module.c 中删除 ModuleNameTask 并将其放在 main.c 中吗?或者只是接受我必须在 module.c 中包含一些 FreeRTOS 的事实。有什么建议吗?

【问题讨论】:

    标签: c embedded portability freertos


    【解决方案1】:

    需要 FreeRTOS 的哪些功能才能使您的模块正常工作。显然有一些东西,或者你不需要包含标题,你也不会调用函数。

    获取这些函数并将它们放在一个名为 os/<operating_sys>/freertos.h 的单独标头中,并将它们包装在您自己的函数名称中(例如 my_createtask(<args>).)。现在要移植到不同的操作系统,您需要为您自己的函数提供一个带有新包装器的新文件。

    如果您做得不好,您会注意到您的 createtask 函数看起来与 FreeRTOS 函数完全一样,并且可以轻松映射,但是当您想要使用 linux/vxWorks/其他操作系统时,该函数没有正确的参数。

    您的 createtask 函数应该只包含您关心的参数。其他的应该在包装器中硬编码。这将使移植更容易(您将拥有与其他操作系统中的硬编码不同的参数)。

    【讨论】:

    • 好的,我想我明白了。因此,我创建了这些将在 module.c 中使用的包装函数(以引用我的示例)。然后这些包装函数使 module.c 操作系统不可知。
    • 是的,就像您为特定于硬件的代码编写一个模块,以便您的程序可以轻松移植到不同的硬件(只需重新编写一个模块)。如果您希望移植到不同的操作系统,应该有一个操作系统模块,这是唯一需要更改的东西。
    • 那么,您是否也将任务创建嵌入到模块中?例如,我拥有的每个模块通常都有一个ModuleNameInit() 函数。如果创建任务功能变得与操作系统无关,在我看来,在模块中创建任务是有意义的。现在,只需调用 init 函数,进程就会启动并运行。关注?
    • 我会在模块中包含与模块相关的所有内容。如果模块需要它自己的任务,那么在模块内部进行设置。正如您所说,一旦它与操作系统无关,就不是问题。
    【解决方案2】:

    同时抽象 RTOS 和设备层。

    定义您设计的操作系统接口(这可能只是 FreeRTOS 功能的子集,甚至包括使用 RTOS 原语实现的更高级别的接口)并使用 FreeRTOS 实现此接口。

    然后,您可以使用您的 RTOS 抽象层接口来定义您的整个应用程序,包括您的设备层。当您将应用程序移植到另一个平台或 RTOS 时,您只需更改抽象层实现,并确保保持与原始实现相同的语义。如果设备层也被适当地抽象出来,以便能够在不同的硬件上通用,那么您可以对硬件依赖项做同样的事情(即从物理实现中抽象出来)。

    多年来,我已成功使用这种方法,使用 C++ 中的 RTOS 抽象,我已将其移植到 FreeRTOS、VxWorks、Segger embOS 和 Keil RTX,甚至 Windows 和 Linux(用于测试和模拟)。您当然不必使用 C++,但它非常适合这项任务。

    在您的抽象中,您需要考虑以下几点:

    • 线程
    • IPC(队列、管道、事件标志、邮箱等)
    • 同步(互斥量、信号量)
    • 定时器
    • 中断处理程序

    您的界面可能看起来与 FreeRTOS 本身非常不同,可能值得查看一些其他 RTOS 界面,看看您可能需要什么样的功能。

    【讨论】: