在RTOS中使用vTaskDelay切换引脚

时间:2017-10-20 07:58:35

标签: delay gpio rtos freertos

我在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-2ms)。

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

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

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

此致

2 个答案:

答案 0 :(得分:0)

以下是一些需要考虑的事项。

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

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

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

  

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

3)在调用taskENTER_CRITICAL周围使用taskEXIT_CRITICALvTaskDelay()对我来说似乎不太好。调用vTaskDelay()的原因是为了让其他任务有机会在此任务延迟时运行。因此,使用taskENTER_CRITICAL禁用中断似乎适得其反。如果您不希望在延迟期间运行其他任务,则调用非阻塞延迟函数而不是vTaskDelay()。然后,如果你的非阻塞功能的时间仍然受到中断的影响,那么你可以考虑将它放入一个关键部分。

答案 1 :(得分:0)

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

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

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

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

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

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

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