You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Arduino双任务运行问题:downLinkDataHandle阻塞prepareTxFrame执行

问题描述

我使用Heltec AD-02设备,希望同时运行void downLinkDataHandle与prepareTxFrame(appPort);。其中downLinkDataHandle包含delay()语句,用于根据下行数据(字节0、1、2)设置LED点亮时长,但执行该函数时,delay()会阻塞prepareTxFrame(appPort);的执行。

修改后的代码

prepareTxFrame函数

/* Prepares the payload of the frame */
static void prepareTxFrame( uint8_t port ) {
  float battV = round((getBatteryVoltage() / 10) / 100); // 测量电池电压
  appDataSize = 1;
  battV = battV * 10; // 准备编码
  appData[0] = battV; // 存储电池电压对应字节
}

downLinkDataHandle函数

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("Delay:");
    Serial.println(delay1);
    uint32_t control = mcpsIndication->Buffer[3];
    if (control == 1) {
      turnOnRGB(color, delay1);
      turnOffRGB();
      delay(delay1);
    };
  };
}
解决方案

要解决delay()阻塞问题,必须用非阻塞式延时替代阻塞式delay(),核心是利用millis()记录时间戳,在主循环中轮询判断延时是否结束,不占用CPU阻塞其他代码。

1. 添加全局状态变量

在代码顶部声明全局变量,用于跟踪LED状态和时间:

bool ledActive = false;       // 标记LED是否处于点亮状态
unsigned long ledStartTime = 0; // LED点亮起始时间戳
uint32_t ledTargetDelay = 0;  // 目标点亮时长
int ledColor = 255;            // LED颜色参数

2. 修改downLinkDataHandle函数

移除阻塞式delay(),仅设置LED参数并启动计时:

void downLinkDataHandle(McpsIndication_t *mcpsIndication) { 
  int port = mcpsIndication->Port;
  if (port == 100) {
    ledColor = 255;
    ledTargetDelay = mcpsIndication->Buffer[0]<<16 | mcpsIndication->Buffer[1]<<8 | mcpsIndication->Buffer[2];
    Serial.print("Delay:");
    Serial.println(ledTargetDelay);
    uint32_t control = mcpsIndication->Buffer[3];
    
    if (control == 1) {
      // 启动LED点亮流程
      ledActive = true;
      ledStartTime = millis();
      turnOnRGB(ledColor, ledTargetDelay);
    } else {
      // 强制关闭LED
      ledActive = false;
      turnOffRGB();
    }
  }
}

3. 在主循环中添加非阻塞控制逻辑

在loop()函数中加入以下代码,实时检查并处理LED状态:

void loop() {
  // 保留原有LoRaWAN流程、prepareTxFrame调用等代码
  
  // 非阻塞LED延时控制
  if (ledActive) {
    if (millis() - ledStartTime >= ledTargetDelay) {
      ledActive = false;
      turnOffRGB();
    }
  }
}

关键说明

  • 该方案下downLinkDataHandle仅负责触发LED动作,不会阻塞后续代码,prepareTxFrame可正常执行。
  • 确保loop()函数中无其他阻塞式操作,保证轮询逻辑能及时响应。

内容的提问来源于stack exchange,提问作者Johan Scheepers

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 03:25:00