Running two tasks at the same time – Arduino

huangapple go评论67阅读模式
英文:

Running two tasks at same time - Arduino

问题

我想运行void downLinkDataHandle:它里面有一个延迟,用来保持LED的亮度,时间由上行设置(字节0、1和2)。如果我执行void downLinkDataHandle,它里面的延迟会阻止prepareTxFrame(appPort);的执行。

我正在使用Heltec AD-02。

我正在使用的代码不幸的是,我不能添加完整的代码,因为stackoverflow说我只是在发布代码。

我用以下内容替换了static void prepareTxFrame

/* 准备帧的有效载荷 */
static void prepareTxFrame( uint8_t port ) {
  float battV = round((getBatteryVoltage() / 10) / 100); // 测量电池电压
  appDataSize = 1;
  battV = battV * 10; //准备编码
  appData[0] = battV; // 电池电压的字节
}

并将void downLinkDataHandle(McpsIndication_t *mcpsIndication)替换为:

void downLinkDataHandle(McpsIndication_t *mcpsIndication) { 
  int port = mcpsIndication->Port;
  if (port ==100) {
    int color = 255;
    uint32_t delay1=mcpsIndication->Buffer[0]<<16|mcpsIndication->Buffer[1]<<8|mcpsIndication->Buffer[2]; // LED亮度的延迟
    Serial.print("延迟:");
    Serial.println(delay1);
    uint32_t control = mcpsIndication->Buffer[3];
    if (control == 1) {
      turnOnRGB(color, delay1);
      turnOffRGB();
      delay(delay1);
    };
  };
}
英文:

I want to run void downLinkDataHandle: it has a delay in it to keep a LED on for time set as from the uplink (Byte 0,1 and 2). If I execute void downLinkDataHandle, the delay in it stops prepareTxFrame(appPort); from been executed.

I am using a Heltec AD-02.

Code I am using Unfortunately I can't add the complete code as stackoverflow says I am posting code only.

I replaced static void prepareTxFrame with

/* Prepares the payload of the frame */
static void prepareTxFrame( uint8_t port ) {
  float battV = round((getBatteryVoltage() / 10) / 100); // measure battery voltage
  appDataSize = 1;
  battV = battV * 10; //prep to encode
  appData[0] = battV; // Byte for Battery voltage
}

And replaced 'void downLinkDataHandle(McpsIndication_t *mcpsIndication)" with

void downLinkDataHandle(McpsIndication_t *mcpsIndication) { 
  int port = mcpsIndication-&gt;Port;
  if (port ==100) {
    int color = 255;
    uint32_t delay1=mcpsIndication-&gt;Buffer[0]&lt;&lt;16|mcpsIndication-&gt;Buffer[1]&lt;&lt;8|mcpsIndication-&gt;Buffer[2]; // Delay for LED on
    Serial.print(&quot;Delay:&quot;);
    Serial.println(delay1);
    uint32_t control = mcpsIndication-&gt;Buffer[3];
    if (control == 1) {
      turnOnRGB(color, delay1);
      turnOffRGB();
      delay(delay1);
    };
  };
}

答案1

得分: 2

你需要忘记阻塞delay函数,开始喜欢millis。以下是一个非阻塞LED闪烁函数的示例:

void handleLed(int pin, unsigned timeOn, unsigned timeOff)
{
    static int stage;
    static unsigned lastMillis = millis();

    if (millis() - lastMillis >= (stage ? timeOn : timeOff))
    {
        digitalWrite(pin, stage);
        stage = !stage;
        lastMillis = millis();
    }
}

void loop(void)
{
    handleLed(13, 500, 200);

    // 这里可以有其他代码,但也不能使用delay函数
}
英文:

You need to forget blocking delay function and start to love millis.

Here you have an example of non blocking LED blinking function

void handleLed(int pin, unsigned timeOn, unsigned timeOff)
{
    static int stage;
    static unsigned lastMillis = millis();

    if(millis() - lastMillis &gt;= (stage ? timeOn : timeOff))
    {
        DigitalWrite(pin, stage);
        stage = !stage;
        lastMillis = millis();
    }
}

void loop(void)
{
    HandleLed(13, 500, 200);

    // he you can have another code - but it also has to do not use delay(functions)
}

答案2

得分: 0

基于@0___________的回答:

如果你想要实际上在一定毫秒数内切换引脚的代码,你可以使用millis() Arduino函数来创建一个由调用者分配的结构体,用于简单的LED/定时器控制。

例如:

typedef struct
{
  uint16_t  time_on;
  uint16_t  time_off;
  uint16_t  count;
  uint16_t  prev_time;
  uint8_t   pin;
  bool      on;
} led_t;

void led_init (led_t* led, uint8_t pin, uint16_t time_on, uint16_t time_off)
{
  led->time_on    = time_on;
  led->time_off   = time_off;
  led->count      = time_on;
  led->prev_time  = millis();
  led->pin        = pin;
  led->on         = true;
}

这里,led由调用者分配,pin是一个引脚号整数,time_ontime_off表示毫秒数。默认情况下,LED会在指定的time_on时间内点亮。

然后,你可以编写一个函数,根据计时器更新这个结构体:

void led_exec (led_t* led)
{
  uint16_t now = millis();
  uint16_t diff = now - led->prev_time;
    
  if(diff > led->count) // 防止下溢
  {
    led->count = 0;
  }
  else                  // 倒计时到零
  {
    led->count -= diff;
  }
    
  if(led->count == 0)        // 当计数到零时,切换LED和计数器
  {
    if(led->on)
    {
      led->count = led->time_off;
    }
    else
    {
      led->count = led->time_on;
    }
    led->on = !led->on;
  }

  digitalWrite(led->pin, led->on);
}

用法:

static led_t led1, led2;
led_init(&led1, 1, 500, 1000);
led_init(&led2, 2, 1000, 2000);

...

void loop (void)
{
  led_exec(&led1);
  led_exec(&led2);
}

这仍然是相当有缺陷和天真的代码,因为计时器周期实际时间取决于程序的繁忙程度。专业程序会使用中断服务例程(ISR),但这段简单的代码可能适用于快速的Arduino项目。我没有测试过它,但它应该能够保持一个LED点亮0.5秒,然后熄灭1秒,同时另一个LED以一半的速度闪烁。

英文:

Based on the answer by @0___________:

If you want something that actually toggles a pin on and off for a stated amount of milliseconds, you could create a caller-allocated struct for your simple LED/timer driver using the crude millis() Arduino function.

For example:

typedef struct
{
  uint16_t  time_on;
  uint16_t  time_off;
  uint16_t  count;
  uint16_t  prev_time;
  uint8_t   pin;
  bool      on;
} led_t;

void led_init (led_t* led, uint8_t pin, uint16_t time_on, uint16_t time_off)
{
  led-&gt;time_on    = time_on;
  led-&gt;time_off   = time_off;
  led-&gt;count      = time_on;
  led-&gt;prev_time  = millis();
  led-&gt;pin        = pin;
  led-&gt;on         = true;
}

Here led is allocated by the caller, pin is a pin number integer, time_on and time_off are times expressed in milliseconds. By default the LED is on, for the time specified by time_on.

You can then write a function that updates this struct based on the timer:

void led_exec (led_t* led)
{
  uint16_t now = millis();
  uint16_t diff = now - last_millis;

  if(diff &gt; led-&gt;count) // prevent underflow
  {
    led-&gt;count = 0;
  }
  else                  // count down to zero
  {
    led-&gt;count -= diff;
  }

  if(count == 0)        // when reaching zero, toggle the LED and counters
  {
    if(led-&gt;on)
    {
      led-&gt;count = time_off;
    }
    else
    {
      led-&gt;count = time_on;
    }
    led-&gt;on = !led-&gt;on;
  }

  DigitalWrite(led-&gt;pin, led-&gt;on);
}

Usage:

static led_t led1, led2;
led_init(&amp;led1, 1,  500, 1000);
led_init(&amp;led2, 2, 1000, 2000);

...

void loop (void)
{
  led_exec(&amp;led1);
  led_exec(&amp;led2);
}

This is still pretty flawed and naive code since the timer cycle real-time depends on how busy your program is. Professional programs would use an ISR instead but this little code might do for quick & dirty Arduino stuff. I haven't tested it but it should keep one LED lit for 0.5s then off for 1s, while another LED is blinks by half that speed.

huangapple
  • 本文由 发表于 2023年4月11日 04:31:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/75980490.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定