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

Arduino串口控制电机异常:遮挡传感器后电机无法自动停止

问题描述

我用Winform GUI连接Arduino控制电机,设置了L(低速)、M(中速)、H(高速)、S(停止)四个按钮,点击按钮向Arduino发送对应字符。配合红外避障传感器(输出接Arduino引脚2),设定电机运行时长:L档3秒、M档5秒、H档10秒、S档停止。但现在遇到问题:遮挡传感器时点击L/M/H按钮,松开手后电机还一直转,只有再次点击L/M/H或S按钮才会停。

Arduino代码

#include<AFMotor.h>
AF_DCMotor motor(4);
int sensor=2;
char sig;
int t;
void setup() {
  Serial.begin(9600);
  pinMode(sensor,INPUT);
}

void loop() {
      t = digitalRead(sensor);
      delay(100);
      sig = Serial.read();
        if(sig=='L')
         {  
              if(t==LOW)
                {
                 runMotor(3000);
                }
               else if(t==HIGH)
                {
                  stopMotor();
                }
         }

         else if(sig=='M')
         {
              if(t==LOW)
                {
                  runMotor(5000);
                }
               else if(t==HIGH)
                {
                  stopMotor();
                }
         } 

         else if(sig=='H')
         {
              if(t==LOW)
                {
                  runMotor(10000);
                }
               else if(t==HIGH)
                {
                 stopMotor();
                }
         } 

         else if(sig == 'S')
          {
                  stopMotor();
          }
}

void runMotor(int n)
{
   motor.setSpeed(200);
   motor.run(FORWARD);
   delay(n);
}

void stopMotor()
{
   motor.setSpeed(200);
   motor.run(RELEASE);
   delay(200);
}

Winform代码

private: System::Void run_Click(System::Object^ sender, System::EventArgs^ e) {
    
        serialPort1->Close();
        serialPort1->Open();
        if (listBox1->Text == "Low")
        {
            serialPort1->Write("L");
        }
        else if (listBox1->Text == "Medium")
        {
            serialPort1->Write("M");
        }
        else if (listBox1->Text == "High")
        {
            serialPort1->Write("H");
        }
        
    
}
private: System::Void stop_Click(System::Object^ sender, System::EventArgs^ e) {
    
    serialPort1->Close();
    serialPort1->Open();
    serialPort1->Write("S");
    
    
}

问题根源

  1. Arduino逻辑缺陷:当前代码只在收到串口指令的瞬间读取一次传感器状态,之后直接进入delay(n)的阻塞延时。延时过程中Arduino完全无法响应传感器状态变化,哪怕你松开手让传感器变为HIGH,电机也会硬跑完设定时长才停。
  2. 串口操作不合理:Winform每次点击按钮都重复关闭再打开串口,容易引发串口冲突,且完全没必要频繁开关。

修复方案

1. 修改Arduino代码(核心逻辑调整)

去掉阻塞式的delay,改用非阻塞的毫秒计时,同时在电机运行过程中持续监测传感器状态,一旦传感器变为HIGH就立即停止电机:

#include<AFMotor.h>
AF_DCMotor motor(4);
const int sensorPin = 2;
char serialCmd = '\0';
unsigned long motorStartTime = 0;
int motorRunDuration = 0;
bool isMotorRunning = false;

void setup() {
  Serial.begin(9600);
  pinMode(sensorPin, INPUT);
  motor.run(RELEASE); // 初始状态停止电机
}

void loop() {
  // 优先处理串口指令
  if (Serial.available() > 0) {
    serialCmd = Serial.read();
    handleSerialCommand(serialCmd);
  }

  // 电机运行时持续监测传感器
  if (isMotorRunning) {
    int sensorState = digitalRead(sensorPin);
    // 传感器未遮挡(HIGH)或到达设定时长,停止电机
    if (sensorState == HIGH || (millis() - motorStartTime >= motorRunDuration)) {
      stopMotor();
    }
  }
}

void handleSerialCommand(char cmd) {
  int sensorState = digitalRead(sensorPin);
  switch(cmd) {
    case 'L':
      if (sensorState == LOW) { // 传感器遮挡时启动
        startMotor(3000);
      } else {
        stopMotor();
      }
      break;
    case 'M':
      if (sensorState == LOW) {
        startMotor(5000);
      } else {
        stopMotor();
      }
      break;
    case 'H':
      if (sensorState == LOW) {
        startMotor(10000);
      } else {
        stopMotor();
      }
      break;
    case 'S':
      stopMotor();
      break;
    default:
      break;
  }
}

void startMotor(int duration) {
  motor.setSpeed(200);
  motor.run(FORWARD);
  motorStartTime = millis();
  motorRunDuration = duration;
  isMotorRunning = true;
}

void stopMotor() {
  motor.run(RELEASE);
  isMotorRunning = false;
}

2. 优化Winform代码(串口操作)

避免重复开关串口,在窗体加载时初始化打开一次,点击按钮直接发送指令:

// 窗体加载时初始化串口
private: System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e) {
    if (!serialPort1->IsOpen) {
        try {
            serialPort1->Open();
        } catch (System::Exception^ ex) {
            MessageBox::Show("串口打开失败:" + ex->Message);
        }
    }
}

private: System::Void run_Click(System::Object^ sender, System::EventArgs^ e) {
    if (!serialPort1->IsOpen) {
        MessageBox::Show("串口未打开");
        return;
    }
    if (listBox1->Text == "Low") {
        serialPort1->Write("L");
    } else if (listBox1->Text == "Medium") {
        serialPort1->Write("M");
    } else if (listBox1->Text == "High") {
        serialPort1->Write("H");
    }
}

private: System::Void stop_Click(System::Object^ sender, System::EventArgs^ e) {
    if (!serialPort1->IsOpen) {
        MessageBox::Show("串口未打开");
        return;
    }
    serialPort1->Write("S");
}

内容的提问来源于stack exchange,提问作者Mr. Nothing

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 00:50:38