【问题标题】:Toggling pins with vTaskDelay in RTOS在 RTOS 中使用 vTaskDelay 切换引脚
【发布时间】:2017-10-20 07:58:35
【问题描述】:

我在 ARM 嵌入式设备上使用 RTOS 发行版。 目前我需要切换这样的信号

GPIO_Write(PIN_1, LOW);
vTaskDelay(msec_to_ticks(1));

GPIO_Write(PIN_1, HIGH);
vTaskDelay(msec_to_ticks(1));
GPIO_Write(PIN_1, LOW);
vTaskDelay(msec_to_ticks(3));

GPIO_Write(PIN_1, HIGH);
if (option1){
    vTaskDelay(msec_to_ticks(3));
    GPIO_Write(PIN_1, LOW);
    vTaskDelay(msec_to_ticks(1));
} else {
    vTaskDelay(msec_to_ticks(1));
    GPIO_Write(PIN_1, LOW);
    vTaskDelay(msec_to_ticks(3));
}
GPIO_Write(PIN_1, HIGH);
if (option2){
    vTaskDelay(msec_to_ticks(3));
    GPIO_Write(PIN_1, LOW);
    vTaskDelay(msec_to_ticks(1));
} else {
    vTaskDelay(msec_to_ticks(1));
    GPIO_Write(PIN_1, LOW);
    vTaskDelay(msec_to_ticks(3));
}
GPIO_Write(PIN_1, HIGH);
vTaskDelay(msec_to_ticks(3));
GPIO_Write(PIN_1, LOW);

我注意到的是,根据我调用此函数(单独的线程/任务)的位置和时间,信号可能完全错误(有时关闭 1-2 毫秒)。

我想知道使用 taskENTER_CRITICAL() 和 taskEXIT_CRITICAL 是否可以帮助我确保信号准确。

我的一个想法是,具有更高优先级的中断可能会启动并延迟某处的代码(尽管我已在任务上设置了最大优先级)。 另一个是时序正确但 GPIO_Write 没有立即发生。

关于如何确保代码不中断的任何其他想法?

问候,

【问题讨论】:

    标签: delay gpio rtos freertos


    【解决方案1】:

    这里有一些事情需要考虑。

    1)vTaskDelay()使用的定时器的周期是多少?延迟期间的错误量可能高达一个刻度。例如,如果您在下一个滴答即将发生之前开始延迟,那么延迟可能会过短一个滴答。

    如果滴答周期为 1 毫秒,则您无法准确测量 1 毫秒的延迟,因为计时器的分辨率相对较低意味着这些延迟可能高达 1 毫秒或 100% 太短。希望滴答周期为 0.01 毫秒或更短,因为这将允许它以 1% 或更小的误差测量 1 毫秒。

    2) FreeRTOS documentation 解释了为什么 vTaskDelay()不是控制周期性任务频率的好方法。

    vTaskDelay() 指定任务希望解除阻塞的时间 相对于调用vTaskDelay() 的时间。例如, 指定 100 滴答的阻塞周期将导致任务解除阻塞 vTaskDelay() 被调用后的 100 个滴答声。 vTaskDelay() 没有 因此提供了一种控制频率的好方法 周期性任务作为通过代码的路径,以及其他 任务和中断活动,将影响频率 vTaskDelay() 被调用,因此是下一个任务的时间 执行。请参阅vTaskDelayUntil() 了解替代 API 函数 旨在促进固定频率执行。它通过 指定绝对时间(而不是相对时间),在该时间 调用任务应该解除阻塞。

    3) 在对vTaskDelay() 的调用周围使用taskENTER_CRITICALtaskEXIT_CRITICAL 对我来说似乎是个坏主意。调用vTaskDelay() 的原因是让其他任务有机会在此任务延迟时运行。因此,使用taskENTER_CRITICAL 禁用中断似乎适得其反。如果您不希望在延迟期间运行其他任务,请调用非阻塞延迟函数而不是 vTaskDelay()。那么如果你的非阻塞函数的时序仍然受到中断的影响,那么也许你可以考虑把它放到临界区。

    【讨论】:

    • 只有第一个转换将与刻度边界异步,因为所有其他转换都会立即遵循延迟。也就是说,如果延迟遵循一个滴答延迟(允许更高优先级的任务和中断),您可以准确地生成 1 个滴答延迟。
    【解决方案2】:

    一个问题是第一个引脚组与 RTOS 时钟异步发生,因此可能发生在时钟周期的任何地方:

    Tick:    |          |          |          |
           ________      __________
    Signal:        |____|          |__________________
              <--------->
           First transition
         may occur anywhere here. 
    

    这可以通过在第一次转换之前插入一个滴答延迟来解决。

    Tick:    |          |          |          |
           __            __________
    Signal:  |__________|          |__________________
    Delay(1)-^         
             Transition occurs on the tick boundary
    

    更高优先级的任务和中断可能会延迟转换并导致抖动,但如果您锁定调度程序或禁用中断,那么这些任务将不会运行,如果您的应用程序可以接受,那么这些任务被分配了不适当的优先级。同样,抖动很重要,然后您的任务再次具有不适当的高优先级或相反的不适当行为和高优先级任务的可调度性。

    任务优先级与“重要性”无关,它与可调度性和截止日期有关。作为指导,具有硬实时截止日期并运行较短确定性周期的任务应具有高优先级。在这种情况下,任务的大部分时间都处于延迟状态 - GPIO 开关将占用很少的时钟周期,因此可以安全地为该任务分配高优先级。

    行为不具有确定性的任务应具有低优先级,以免影响时间关键任务。如果此片段是某些任务的一部分,该任务执行其他可能不确定的事情,那么您的任务分区可能需要重新考虑。任务划分并不总是与“工作”有关,它再次与可调度性有关,并且可能需要在多个任务中拆分直观的单一特征或行为。例如,这个信号可能是由一个高优先级任务等待某个低优先级任务触发的事件产生的,而不是直接在低优先级任务中实现。

    【讨论】:

      猜你喜欢
      • 2021-07-19
      • 1970-01-01
      • 1970-01-01
      • 2015-04-13
      • 1970-01-01
      • 2011-03-03
      • 1970-01-01
      • 2013-05-22
      • 1970-01-01
      相关资源
      最近更新 更多