【问题标题】:Arduino, delay in a task schedulerArduino,任务调度程序中的延迟
【发布时间】:2014-04-26 14:59:56
【问题描述】:

我目前遇到一个问题,其中涉及使用任务调度程序的程序和使用延迟的任务。

一个任务正在运行以下代码:

// Some function
delay(_speedVar);
// Some function
delay(_speedVar);
// End of task.

因为我还有另一个任务,只是从 UART 轮询信息,所以设置 _speedVar 的值。

// Uart task
if(Serial.available())
{
  _speedVar = Serial.read();
}
// End of task

我的问题是,如果 speedVar 设置为一个高值,比如 10 秒,那么执行某些功能且延迟为 (_speedVar) 的任务需要以某种方式中断,并使用新的 _speedVar 值重新开始.

我使用的任务计划程序实际上没有灵活性。它只允许我创建和销毁任务。我还没有找到一个有更多功能并且可能有效的,所以我现在坚持使用这个

解决方案的唯一想法是使用中断,但我不确定在使用任务调度程序时如何正确实现这一点。

所有编程都是使用 Arduino 的 Sketch 工具在 C++ 中完成的。编程单元是一个 Arduino Uno。

【问题讨论】:

  • 您说的是 C/C++,但只标记了 C - C 或 C++ - 它不能同时是两者。
  • 带有下划线前缀的严格符号保留供编译器及其标准库实现使用。
  • 使用可信的多任务操作系统并停止轮询。
  • 抱歉没有说明清楚。我对 c/c++ 的意思是在 Arduino 的嵌入式 C 程序中实现 C++ 类。对于操作系统,我一直使用meatandnetworking.com/code/… 来安排任务。我所希望的是一些功能,就像你在 FreeRTOS 中所拥有的一样,带有 taskPause 功能。基本上将任务置于阻塞状态 x ms,然后将其移回就绪队列。

标签: c++ arduino embedded interrupt scheduler


【解决方案1】:

假设调度程序是协作的,并且您发布的这些代码片段以某种方式在某个“大循环”中被调用,那么大多数非平凡任务通常会被实现为状态机。给定:

class cElapsedTime
{
    cElapsedTime()
    {
       zero() ; 
    }

    void zero()
    {
        timestamp = millis() ;
    }

    bool time()
    {
        return millis() - m_timestamp ;
    }
} ;

enum
{
    STATE_A,
    STATE_B
}  state = STATE_A;

cElapsedTime control_task_delay ;

然后在两个状态之间切换以在每个延迟周期后执行不同的代码块。通过不断地将经过的时间与_speedVar当前 值进行比较,可以随时更改延迟。如果_speedVar从10秒变为5秒,经过时间为7秒,延迟代码将立即执行;如果时间延长,延迟也会:

if( control_task_delay.time() >= _speedVar )
{
    switch( state )
    {
        case STATE_A :
            // Some function

            control_task_delay.zero()      // Restart delay
            state = STATE_B ;              // Next state
        break ;

        case STATE_B :
            // Some function

            control_task_delay.zero()      // Restart delay
            state = STATE_A ;              // Next state
        break ;
    }
}

在您的代码片段中不清楚第一个// Some function 与第二个不同;也许// Some other function 会澄清?但是,如果它们实际上是相同的,那么代码将很简单:

if( control_task_delay.time() >= _speedVar )
{
    // Some function

    control_task_delay.zero()      // Restart delay
}

您可以看到,这与您应用于 UART 轮询任务的原理相同 - 使用非阻塞测试。也就是说,在任何情况下都可能不需要单独的任务;你可以:

if( Serial.available() )
{
    _speedVar = Serial.read();
}

if( control_task_delay.time() >= _speedVar )
{
    switch( state )
    {
        case STATE_A :
            // Some function

            control_task_delay.zero()      // Restart delay
            state = STATE_B ;              // Next state
        break ;

        case STATE_B :
            // Some function

            control_task_delay.zero()      // Restart delay
            state = STATE_A ;              // Next state
        break ;
    }
}

在您的代码片段中不清楚第一个// Some function 与第二个不同;也许// Some other function 会澄清?但是,如果它们实际上是相同的,那么代码将很简单:

if( control_task_delay.time() >= _speedVar )
{
    // Some function

    control_task_delay.zero()      // Restart delay
}

if( control_task_delay.time() >= _speedVar )
{
    switch( state )
    {
        case STATE_A :
            // Some function

            control_task_delay.zero()      // Restart delay
            state = STATE_B ;              // Next state
        break ;

        case STATE_B :
            // Some function

            control_task_delay.zero()      // Restart delay
            state = STATE_A ;              // Next state
        break ;
    }
}

很难看出“调度程序”在这种情况下实现了什么。

【讨论】:

  • 非常感谢您的回复。很抱歉缺少描述。它使用了两个单独的功能。肯定会尝试您的解决方案并返回答案:) 但是在这种情况下可能会反对使用调度程序。但是,我总共运行 3 个任务。一个做延迟的人,你刚刚给出了一个可能的解决方案。另一个运行 FSM 的任务,跟踪 UART 输入和 FSM 上的任何变化。最后一个是为传感器读数而保存的,尚未实现。
  • 试过你的解决方案,它就像一个魅力。非常感谢您的帮助:)
  • @user3008529 :不客气。我感谢您是 StackOverflow 的新手,但如果这是一个可以接受的答案,您可能希望将其选为接受。如果发布了更好的答案,您可以随时取消选择它。
  • 我接受了您的回答。在这样的小程序中看不到替代答案的原因。
  • @user3008529 :嗯,这是我的第二个答案 - 我可能还有一个更好的答案 ;-)
【解决方案2】:

协作任务调度程序的任务不能包含延迟或阻塞 IO 操作。 相反,您需要计算刻度以匹配您需要的时间(在 arduino 上,我猜您可以使用 http://arduino.cc/en/Reference/millis

【讨论】:

  • 感谢您的评论。研究了该解决方案,我遇到的使用带有 millis() 的计时器进行比较的是,任务现在正在停止其他任务,这使得任务调度程序的使用可以忽略不计:)
  • @user3008529 :HLL 没有提供使用milis() 的解决方案,他只是提到了一个。 您的解决方案 不起作用这一事实并不意味着没有使用它的解决方案,只是您的解决方案不起作用。那么我们是否假设您的调度程序合作的?这将是包含在您的问题中的有用信息。不仅不能在协作调度中使用阻塞调用,也不能使用 busy-wait 循环。
猜你喜欢
  • 1970-01-01
  • 2013-05-29
  • 2018-10-21
  • 2014-10-28
  • 1970-01-01
  • 1970-01-01
  • 2015-10-31
  • 1970-01-01
  • 2015-09-14
相关资源
最近更新 更多