[假装新篇] 再探 红外+舵机+电机

Author Avatar
MonsterX 5月1日 发布 | 05月14日最后更新
  • 在其它设备中阅读本文章

重新写了舵机与风扇共存的代码,这次感觉逻辑上问题少了一点,但似乎还是存在我没发现的错误。当舵机开始摇头时任何代码都无法执行了,开始持续接收到“幽灵”红外信号,初步判断是舵机运行后红外信号解码出错。
先挂在这里等待检查,不知道有没有路过的大佬能帮我康康...

接线:
  数字引脚 3   -> 舵机
  数字引脚 5~  -> 电机1
  数字引脚 6~  -> 电机2
  数字引脚 8   -> 按键开关
  数字引脚 11  -> 红外接收传感器

根据网上资料 <Servo.h> 会占用 9,10 号引脚的定时器,所以电机我给接到 5,6 引脚。电机为 130 电机,用 ULN2003 步进电机驱动模块驱动,详情可以看一下前面的 Arduino 文章。

#include <IRremote.h>
#include <Servo.h>

const int motorIn1 = 5;
const int motorIn2 = 6;
const int buttonPin = 8;
const int irReceiverPin = 11;
const int ledPin = 13;

int fanspeed = 0;
int btState;
int lastbtState = LOW;
long lastDbTime = 0;
long dbDelay = 60;

Servo myservo;
int djstate = 0;
int anglelast = 90;
int djdirection = 1;
int djangle;

IRrecv irrecv(irReceiverPin);
decode_results results;


void setup() {
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(motorIn1, OUTPUT);
  pinMode(motorIn2, OUTPUT);
  myservo.attach(3);
  myservo.write(90);
  delay(1000);
  Serial.begin(9600);
  irrecv.enableIRIn();
}

void loop() {
startfan:
  int reading = digitalRead(buttonPin);
  if (reading != lastbtState) {
    lastDbTime = millis();
  }
  if ((millis() - lastDbTime) > dbDelay) {
    if (reading != btState) {
      btState = reading;
      if (btState == HIGH) {
        digitalWrite(ledPin, HIGH);
        fanspeed = fanspeed + 1;
        if (fanspeed >= 4) {
          fanspeed = 0;
        }
      }
      else
        digitalWrite(ledPin, LOW);
    }
  }
  lastbtState = reading;

  if (irrecv.decode(&results)) {
    digitalWrite(ledPin, HIGH);
    Serial.print("Detail Information: irCode:");
    Serial.println(results.value, HEX);
    switch (results.value) {
      case 0xFF22DD:
        Serial.println("Button |<< had been pressed.");
        fanspeed = fanspeed - 1;
        if (fanspeed <= 0) {
          fanspeed = 0;
        }
        Serial.println("fanspeed - 1. Finished.");
        break;
      case 0xFF02FD:
        Serial.println("Button >>| has been pressed.");
        fanspeed = fanspeed + 1;
        if (fanspeed >= 3) {
          fanspeed = 3;
        }
        Serial.println("fanspeed + 1. Finished.");
        break;
      case 0xFF629D:
        Serial.println("Button CH has been pressed.");
        fanspeed = 0;
        Serial.println("You have turn down the fan.");
        break;
      case 0xFF30CF:
        Serial.println("Button 1 has been pressed.");
        fanspeed = 1;
        Serial.println("fanspeed = 1. Finished.");
        break;
      case 0xFF18E7:
        Serial.println("Button 2 has been pressed.");
        fanspeed = 2;
        Serial.println("fanspeed = 2. Finished.");
        break;
      case 0xFF7A85:
        Serial.println("Button 3 has been pressed.");
        fanspeed = 3;
        Serial.println("fanspeed = 3. Finished.");
        break;
      case 0xFFE21D:
        Serial.println("Button CH+ has been pressed.");
        if (fanspeed != 0) {
          djstate = 1;
          Serial.println("Start servo. Finished.");
        }
        Serial.println("Start failed, start fan firstly.");
        break;
      case 0xFFA25D:
        Serial.println("Button CH- has been pressed.");
        anglelast = myservo.read();
        djstate = 0;
        Serial.println("Shut down servo. Finished.");
        break;
    }
    delay(600);
    while (!irrecv.isIdle());
    irrecv.resume();
    digitalWrite(ledPin, LOW);
  }

  while (djstate == 1) {
    if (djdirection = 1) {
      for (djangle = anglelast; djangle <= 160; djangle += 1) {
        myservo.write(djangle);
        delay(15);
        if (djangle == 160) {
          anglelast = myservo.read();
          djdirection = 2;
          break;
        }
        djcontrol();
      }
    }
    if (djdirection = 2) {
      for (djangle = anglelast; djangle >= 20; djangle -= 1) {
        myservo.write(djangle);
        delay(15);
        if (djangle == 20) {
          anglelast = myservo.read();
          djdirection = 1;
          break;
        }
        djcontrol();
      }
    }
  }

  switch (fanspeed) {
    case 1: analogWrite(motorIn1, 0); analogWrite(motorIn2, 150); break;
    case 2: analogWrite(motorIn1, 0); analogWrite(motorIn2, 200); break;
    case 3: analogWrite(motorIn1, 0); analogWrite(motorIn2, 250); break;
    default: analogWrite(motorIn1, 0); analogWrite(motorIn2, 0); break;
  }
}

void djcontrol() {
        if (irrecv.decode(&results) && results.value == 0xFF629D) {
          anglelast = myservo.read();
          goto startfan;
        }
        if (irrecv.decode(&results) && results.value == 0xFFA25D) {
          anglelast = myservo.read();
          goto startfan;
        }
        if (irrecv.decode(&results) && results.value == 0xFF30CF) {
          fanspeed = 1;
        }
        if (irrecv.decode(&results) && results.value == 0xFF18E7) {
          fanspeed = 2;
        }
        if (irrecv.decode(&results) && results.value == 0xFF7A85) {
          fanspeed = 3;
        }
        if (irrecv.decode(&results) && results.value == 0xFF906F) {
          anglelast = myservo.read();
          djdirection = !djdirection;
          break;
        }
        if (irrecv.decode(&results) && results.value == 0xFF22DD) {
          fanspeed = fanspeed - 1;
          if (fanspeed <= 0) {
            fanspeed = 0;
            anglelast = myservo.read();
            goto startfan;
          }
        }
        if (irrecv.decode(&results) && results.value == 0xFF02FD) {
          fanspeed = fanspeed + 1;
          if (fanspeed >= 3) {
            fanspeed = 3;
          }
        }
}

感觉还是代码逻辑的问题:这个 while() 里又放 for() 的写法感觉不合适。改一改,嗯。待更

还有一个想法,不解决问题,但是尽可能让摇头和原来的功能“兼容”。既然摇头的时候啥也干不了,那我就定时让你摇个 10s 强制停止 hhhhh 我可真是个小机灵鬼啊 成功让程序变得更加冗余。

#include <IRremote.h>
#include <Servo.h>

const int motorIn1 = 5;
const int motorIn2 = 6;
const int buttonPin = 8;
const int irReceiverPin = 11;
const int ledPin = 13;

int fanspeed = 0;
int btState;
int lastbtState = LOW;
long lastDbTime = 0;
long dbDelay = 60;

Servo myservo;
int djstate = 0;
int anglelast = 90;
int djdirection = 1;
int djangle;
long starttime = 0;          // 摇头开始时间
long runtime = 0;            // 摇头运行时间

IRrecv irrecv(irReceiverPin);
decode_results results;


void setup() {
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(motorIn1, OUTPUT);
  pinMode(motorIn2, OUTPUT);
  myservo.attach(3);
  myservo.write(90);
  Serial.begin(9600);
  irrecv.enableIRIn();
}


void loop() {
  startfan:
  int reading = digitalRead(buttonPin);
  if (reading != lastbtState) {
    lastDbTime = millis();
  }
  if ((millis() - lastDbTime) > dbDelay) {
    if (reading != btState) {
      btState = reading;
      if (btState == HIGH) {
        digitalWrite(ledPin, HIGH);
        fanspeed = fanspeed + 1;
        if (fanspeed >= 4) {
          fanspeed = 0;
        }
      }
      else
        digitalWrite(ledPin, LOW);
    }
  }
  lastbtState = reading;


  if (irrecv.decode(&results)) {
    digitalWrite(ledPin, HIGH);
    Serial.print("Detail Information: irCode:");
    Serial.println(results.value, HEX);
    switch (results.value) {
      case 0xFF22DD:
        Serial.println("Button |<< had been pressed.");
        fanspeed = fanspeed - 1;
        if (fanspeed <= 0) {
          fanspeed = 0;
          Serial.println("Fan is running at min speed.");
        }
        else 
          Serial.println("fanspeed - 1. Finished.");
        break;
      case 0xFF02FD:
        Serial.println("Button >>| has been pressed.");
        fanspeed = fanspeed + 1;
        if (fanspeed >= 3) {
          fanspeed = 3;
          Serial.println("Fan is running at max speed.");
        }
        else
          Serial.println("fanspeed + 1. Finished.");
        break;
      case 0xFF629D:
        Serial.println("Button CH has been pressed.");
        fanspeed = 0;
        myservo.write(90);                      // 风扇关闭时舵机归中
        Serial.println("You have turn down the fan.");
        break;
      case 0xFF30CF:
        Serial.println("Button 1 has been pressed.");
        fanspeed = 1;
        Serial.println("fanspeed = 1. Finished.");
        break;
      case 0xFF18E7:
        Serial.println("Button 2 has been pressed.");
        fanspeed = 2;
        Serial.println("fanspeed = 2. Finished.");
        break;
      case 0xFF7A85:
        Serial.println("Button 3 has been pressed.");
        fanspeed = 3;
        Serial.println("fanspeed = 3. Finished.");
        break;
      case 0xFFE21D:
        Serial.println("Button CH+ has been pressed.");
        if(fanspeed != 0){
          djstate = 1;
          starttime = millis();                 // 风扇摇头时开始计时
          Serial.println("Start servo. Finished.");
        }
        else
          Serial.println("Start failed, start fan firstly.");
        break;
      case 0xFFA25D:
        Serial.println("Button CH- has been pressed.");
        anglelast = myservo.read();
        djstate = 0;
        Serial.println("Shut down servo. Finished.");
        break;
    }
    delay(600);
    irrecv.resume();
    digitalWrite(ledPin, LOW);
  }


  while (djstate==1) {
    runtime = millis();                         // 注意这里,添加风扇转动计时
    if (runtime - starttime >= 10000) {         // 让风扇摇头 10s 自动停止
      anglelast = myservo.read();
      djstate = 2;
      break;
    }
    if (djdirection = 1) {
      for (djangle = anglelast; djangle <= 140; djangle += 1) {
        myservo.write(djangle);
        delay(30);
        if (djangle == 140) {
          anglelast = myservo.read();
          djdirection = 2;
          break;
        }
        /* 试图控制 */
      }
    }
    if (djdirection = 2) {  
      for (djangle = anglelast; djangle >= 40; djangle -= 1) {
        myservo.write(djangle);
        delay(30);
        if (djangle == 40) {
          anglelast = myservo.read();
          djdirection = 1;
          break;
        }
        /* 试图控制 */
      }
    }
  }


  switch (fanspeed) {
    case 1: analogWrite(motorIn1, 0); analogWrite(motorIn2, 150); break;
    case 2: analogWrite(motorIn1, 0); analogWrite(motorIn2, 200); break;
    case 3: analogWrite(motorIn1, 0); analogWrite(motorIn2, 250); break;
    default: analogWrite(motorIn1, 0); analogWrite(motorIn2, 0); break;
  }
}

还想过一种方法,用 loop() 函数循环执行的特性减少 for() 循环的应用,大概像这样:

int anglestep = 10;
 
void loop() {
    djangle = djangle + anglestep;
    if (djangle = 160 || djangle = 20) {
        anglestep = - anglestep;
    }
    myservo.write(djangle);
}

void loop() {
     
    /* 原主要代码 */
     
    while(djstate = 1) {
        myservo.write(djangle);
        djangle = djangle + anglestep;
        if (djangle = 160 || djangle = 20) {
            anglestep = - anglestep;
        }
        if (irrecv.decode(&result) || btstate = HIGH) {
            djangle = myservo.read();
            break;
        }
    }
}

但是又考虑到 loop() 函数里由于别的功能需要(比如红外解码延时激活传感器)写了别的 delay() ,可能会导致风扇摇头一卡一卡的体验不佳。暂时还未测试。

本文链接:https://monsterx.cn/Microchips/help-me-for-my-sg90-fan.html
本站文章除特殊说明外全部由 MonsterX 原创发布,未经允许禁止以任何形式转载。
如果您发现以上内容含有任何引起不适/侵犯权利/违反法律的内容,请立即 联系站长 进行处理。

选择表情