我正在用ESP32制作一盏灯,我选择的HomeKit库使用了FreeRTOS和esp-idf,我对此并不熟悉。
目前,我有一个函数,每当光线的颜色应该改变时,就会调用它,它只是一步一步地改变它。我想让它在不同颜色之间褪色,这需要一个运行一两秒钟的功能。让这个块作为程序的主要执行显然会使它反应迟钝,所以我需要让它作为一个任务运行。
我面临的问题是,我一次只想运行淡入淡出功能的一个副本,如果在完成之前第二次调用它,那么在启动第二个副本之前,第一个副本应该退出(不需要等待完全淡入淡出时间)。
我找到了vTaskDelete
,但如果我只是在任意点终止淡入淡出函数,一些变量和LED本身将处于未知状态。为了解决这个问题,我考虑使用一个"kill flag"全局变量,衰落函数将在其每个循环中检查该变量。
这是我想到的伪代码:
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)
}
}
我的主要问题是:
- 这是最好的方法还是有更好的选择
- 如果可以的话,我的
wait_for_fade_to_die
的等效值是多少?我在周围的短暂浏览中找不到任何东西,但我是FreeRTOS的新手
我很抱歉地说,我的印象是你在试图解决你的具体问题时走错了路。你写的是你不熟悉FreeRTOS和esp-idf,所以我建议你首先熟悉FreeRTOS(或RTOS的概念,或任何其他RTOS,将这些知识转移到FreeRTOS,…)
在执行此操作时,您会注意到(除了一些特定示例之外)任务与函数完全不同,后者是为单个作业的顺序"批处理"而编写的。
模型与理论
通常,在嵌入式系统中设计一个好的RTOS任务时,最有用的模型是状态机,它接收事件并对其做出反应,可能更改其状态和/或执行一些操作,这些操作的起点和有效载荷取决于状态机接收到的事件以及检测到事件时的状态。当没有事件时,任务不应空闲,而是在RTOS功能创建的某个屏障处阻止。RTOS功能应提供下一个相关事件。
实现这样的任务意味着编程一个任务函数,该任务函数由一个简短的初始化块组成,然后是一个无限循环,该循环首先调用RTOS库以获得下一个逻辑事件(见下文…),然后是处理该逻辑事件的代码。现在,逻辑事件不必由RTOS事件表示(虽然这在简单的情况下可能发生),但也可以由RTOS队列、邮箱或其他方式实现。在这样的设计模式中,基于RTOS的软件的任务"永远"存在,等待下一个作业执行。
如何将理论应用于你的问题
您必须检查如何将编程问题分解为不同的任务。
目前,我有一个函数,只要灯光的颜色应该改变,就会调用它,它只是一步一步地改变它。我想让它在不同颜色之间褪色,这需要一个运行一两秒钟的功能。让这个块作为程序的主要执行显然会使它反应迟钝,所以我需要让它作为一个任务运行。
我希望我能正确理解您的应用程序的目标:该系统正在驱动不同颜色的多个光源,一些"请求源"正在选择要显示的下一种颜色。当要求使用不同的颜色时,不应立即进行更改,但在一定时间内会出现一些"褪色"现象。即使发生衰落,系统(及其请求源)也应保持响应,可能会在在中间改变衰落的方向。
我想你没有说颜色要求是从哪里来的。因此,我猜测这个请求源可能是一些按钮、串行接口或后台运行的复杂算法(或随机数生成器?)。现在真的不重要了。
我面临的问题是,我一次只想运行淡入淡出函数的一个副本,如果在完成之前第二次调用它,则在启动第二个副本之前,第一个副本应该退出(无需等待完全淡入淡出时间)。
您主要关注的是如何在任何时候更改状态(此处:光褪色的目标颜色),以便旧的、正在进行的褪色过程变得过时,但输出(=光)行为不会以不连续的方式改变。
我建议您设置以下任务:
-
从…生成颜色更改请求的一个(或多个)任务。。。你在这里需要什么。
-
一项任务是评估当前应输出的颜色混合。该任务应准备好接收
- 一个新的颜色请求(在不更改当前颜色混合值的情况下更改"目标颜色"状态)
- 周期性的滴答事件(例如,来自硬件或软件计时器)使颜色混合值更新为当前目标颜色的方向
-
零、一个或多个任务,通过驱动系统的输出功能来实现颜色混合值(例如,配置GPIO或PWM,或通过串行连接传输信息……我们不知道)。如果调整输出部分只是分配一些寄存器,那么"零"在这里是正确的。否则,请尝试"一个或多个"。
现在该怎么办
我找到了vTaskDelete,但如果我只是在任意点终止淡入淡出功能,一些变量和LED本身将处于未知状态。为了解决这个问题,我考虑使用一个"kill flag"全局变量,衰落函数将在其每个循环中检查该变量。
只是不要那样做。杀死一个任务,即使是一个没有为从内部杀死做准备的任务,也会导致对软件管理和清理输出内容的需求的跟进,你最终会想知道为什么你开始使用RTOS。
我知道,在你从未这样做过的情况下,开始以这种方式设计和编程是一项巨大的努力,就像跳进冷水中一样。请相信我,通过这种方式,你将学习如何设计和实现伟大的嵌入式系统的基础知识。专业教育公司提供关于RTOS集成、响应式编程和状态机设计的课程,价格为数千美元/欧元/英镑,这是这类工作知识的一个很好的指标。
祝你好运!在这个过程中,你会遇到很多详细的问题,欢迎你发布到这个板上(或在上找到早期的答案)。