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

Arduino HC-06蓝牙控制代码快速点击按钮执行两次的解决方法

解决方案

问题根源

快速点击按钮时,蓝牙模块会连续发送A(按下)和0(松开)指令,但原代码的while循环会阻塞程序,无法及时响应0信号;同时串口缓冲区的残留字符也会导致动作重复触发。此外,delay()函数会完全阻塞程序,让串口处理滞后。

修改思路

  1. 改用状态机模式:用全局变量标记伺服运行状态,替代阻塞式的while循环,确保程序能实时响应串口输入。
  2. 非阻塞延迟:用millis()替代delay(),避免程序被卡住,保证串口指令能被及时处理。
  3. 清空串口缓冲区:每次处理串口前清空残留数据,避免旧指令干扰。

修改后的代码

#include <Servo.h>

Servo servo1U;
Servo servo1L;
Servo servo2U;
Servo servo2L;
Servo servo3U;
Servo servo3L;
Servo servo4U;
Servo servo4L;
 
int neutral = 90;

int front_back = 0;
int back_forward = 180;
int up = 90;
int down = 170;

// 状态标记:是否正在执行伺服动作
bool isRunning = false;
// 非阻塞延迟用的时间戳
unsigned long lastActionTime = 0;
// 动作阶段标记(0-3对应原代码的4个动作步骤)
int actionPhase = 0;
const long actionInterval = 500; // 每个动作步骤的间隔时间

void setup() {
  Serial.begin(9600);

  servo1U.attach(9);
  servo1L.attach(2);
  servo2U.attach(3);
  servo2L.attach(4);
  servo3U.attach(5);
  servo3L.attach(6);
  servo4U.attach(7);
  servo4L.attach(8);

  // 初始化伺服到默认位置
  servo1U.write(neutral);
  servo2U.write(neutral);
  servo3U.write(back_forward);
  servo4U.write(180 - back_forward);

  servo1L.write(down);
  servo2L.write(180 - down);
  servo3L.write(down);
  servo4L.write(180 - down);
}

void loop() {
  // 处理串口输入:先清空缓冲区残留数据,只取最新的指令
  while (Serial.available() > 0) {
    char cha = Serial.read();
    if (cha == 'A') {
      isRunning = true;
    } else if (cha == '0') {
      isRunning = false;
      // 停止时重置动作阶段
      actionPhase = 0;
    }
  }

  // 如果处于运行状态,执行伺服动作(非阻塞)
  if (isRunning) {
    unsigned long currentTime = millis();
    if (currentTime - lastActionTime >= actionInterval) {
      lastActionTime = currentTime;
      
      switch(actionPhase) {
        case 0:
          servo1U.write(180 - front_back);
          servo2U.write(front_back);
          servo3U.write(neutral);
          servo4U.write(neutral);
          break;
        case 1:
          servo1L.write(up);
          servo2L.write(180 - up);
          servo3L.write(up);
          servo4L.write(180 - up);
          break;
        case 2:
          servo1U.write(neutral);
          servo2U.write(neutral);
          servo3U.write(back_forward);
          servo4U.write(180 - back_forward);
          break;
        case 3:
          servo1L.write(down);
          servo2L.write(180 - down);
          servo3L.write(down);
          servo4L.write(180 - down);
          break;
      }

      // 切换到下一个动作阶段,循环执行
      actionPhase = (actionPhase + 1) % 4;
    }
  }
}

关键修改说明

  • 状态机替代while循环:isRunning变量标记是否需要执行动作,程序不再被阻塞,能实时响应串口的0指令,快速点击时会立即停止。
  • 非阻塞延迟:用millis()记录上次动作时间,确保每个动作步骤间隔500ms,但不会阻塞串口处理。
  • 清空串口缓冲区:用while(Serial.available() > 0)循环读取所有残留字符,只保留最新的指令,避免旧的A导致重复触发。
  • 动作阶段拆分:把原代码的4个连续动作拆分为阶段,每次循环执行一个阶段,保证动作逻辑和原代码一致,但更灵活可控。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 22:24:57