2

我正在使用 ESP32 和我选择的 HomeKit 库使用我不熟悉的 FreeRTOS 和 esp-idf。

目前,我有一个函数,只要应该改变光的颜色,就会调用它,它只是一步一步地改变它。我想让它在颜色之间褪色,这需要一个运行一两秒的函数。有了这个块,程序的主要执行显然会使其完全没有响应,所以我需要让它作为一个任务运行。

我面临的问题是我只希望一次运行一个淡入淡出功能的副本,如果在它完成之前第二次调用它,第一个副本应该退出(不等待完整的淡入淡出时间)之前开始第二个副本。

我发现了vTaskDelete,但如果我只是在任意点终止淡入淡出功能,一些变量和 LED 本身将处于未知状态。为了解决这个问题,我想使用一个“kill flag”全局变量,fading 函数将检查它的每个循环。

这是我正在考虑的伪代码:

update_light {
    kill_flag = true
    wait_for_fade_to_die
    xTaskCreate fade
}

fade {
    kill_flag = false
    loop_1000_times {
        (fading code involving local and global variables)
        .
        .
        if kill_flag, vTaskDelete(NULL)
        vTaskDelay(2 / portTICK_RATE_MS)
    }
}

我的主要问题是:

  • 这是最好的方法还是有更好的选择?
  • 如果这没问题,什么是相当于 my wait_for_fade_to_die?我无法从短暂的环顾中找到任何东西,但我是 FreeRTOS 的新手。
4

1 回答 1

3

很抱歉,我的印象是你在试图解决你的具体问题时几乎走错了路。您正在写您不熟悉 FreeRTOS 和 esp-idf,所以我建议您首先熟悉 freeRTOS(或一般的 RTOS 概念或任何其他 RTOS,将这些知识转移到 freeRTOS,...) .

这样做时,您会注意到(除了一些特定示例之外)任务与为单个作业的顺序“批处理”处理而编写的函数完全不同。

模型与理论

通常,在嵌入式系统中设计一个好的 RTOS 任务时,最有用的模型是状态机,它接收事件并对其做出反应,可能会更改其状态和/或执行一些动作,其起点和有效载荷取决于状态机接收到的事件以及检测到事件时所处的状态。在没有事件的情况下,任务不应空闲,而是阻塞在由 RTOS 功能创建的某个屏障处,该功能应该传递下一个相关事件。

实现这样的任务意味着编写一个任务函数,该函数由一个简短的初始化块和一个无限循环组成,该循环首先调用 RTOS 库以获取下一个逻辑事件(见下文...),然后是处理该逻辑事件的代码. 现在,逻辑事件不必由 RTOS 事件表示(虽然这可能发生在简单的情况下),但也可以由 RTOS 队列、邮箱或其他实现。在这样的设计模式中,基于 RTOS 的软件的任务“永远”存在,等待下一个工作执行。

如何将理论应用于您的问题

您必须检查如何将您的编程问题分解为不同的任务。

目前,我有一个函数,只要改变灯光的颜色,就会调用它,它只是一步一步地改变它。我想让它在颜色之间褪色,这需要一个运行一两秒的函数。有了这个块,程序的主要执行显然会使其完全没有响应,所以我需要让它作为一个任务运行。

我希望我正确理解了您的应用程序的目标:系统正在驱动多个不同颜色的光源,并且一些“请求源”正在选择要显示的下一种颜色。当请求不同的颜色时,更改不会立即执行,而是在一定时间内会出现一些“褪色”。即使发生淡入淡出,系统(及其请求源)也应保持响应,可能会在中间改变淡入淡出的方向。

我想你没有说颜色请求来自哪里。因此,我猜测这个请求源可能是一些按钮、串行接口或在后台运行的复杂算法(或随机数生成器?)。现在真的不重要了。

我面临的问题是我只希望一次运行一个淡入淡出功能的副本,如果在它完成之前第二次调用它,第一个副本应该退出(不等待完整的淡入淡出时间)之前开始第二个副本。

您本质上要寻找的是如何随时更改状态(此处:光褪色的目标颜色),以便旧的、正在进行的褪色过程变得过时,但输出(=光)行为不会以不连续的方式改变.

我建议您设置以下任务:

  • 一个(或多个)任务从...生成颜色更改请求,无论您在此处需要什么。

  • 评估当前应输出哪种颜色混合的一项任务。该任务应准备好接收

    1. 新颜色请求(更改“目标颜色”状态而不更改当前颜色混合值)
    2. 导致颜色混合值更新为当前目标颜色方向的周期性滴答事件(例如,来自硬件或软件计时器)
  • 零个、一个或多个任务通过驱动系统的输出特性来实现颜色混合值(例如,配置 GPIO 或 PWM,或通过串行连接传输信息……我们不知道)。如果调整输出部分只是分配一些寄存器,那么这里的“零”对你来说是正确的。否则,请尝试“一个或多个”。

现在要做什么

我找到了 vTaskDelete,但如果我只是在任意点终止淡入淡出功能,一些变量和 LED 本身将处于未知状态。为了解决这个问题,我想使用一个“kill flag”全局变量,fading 函数将检查它的每个循环。

只是不要那样做。杀死一项任务,即使是一个没有准备好从内部杀死的任务,也会导致后续要求通过您的软件来管理和清理输出内容,您最终会想知道为什么您甚至开始使用 RTOS。

我确实知道,在你从未这样做过的情况下开始以这种方式进行设计和编程是一项巨大的努力,就像跳入冷水一样开始。请相信我,这样您将学习如何设计和实现出色的嵌入式系统的基础知识。专业教育公司以数千美元/欧元/英镑的价格提供有关 RTOS 集成、响应式编程和状态机设计的课程,这很好地表明了这种工作知识。

祝你好运!在此过程中,您会遇到很多详细的问题,欢迎您将这些问题发布到此版块(或在上面找到较早的答案)。

于 2020-06-03T22:21:07.090 回答