Работа двигателя в течение 3 секунд непрерывно с прерыванием и без него

Я подключил двигатель постоянного тока и ИК-датчик к своему nano. Двигатель постоянного тока должен работать только в том случае, если ИК-датчик обнаруживает препятствие. Теперь я пытаюсь заставить двигатель выключаться, если он непрерывно блокируется в течение 3 секунд, и выходить из прерывания (в случае первого кода с прерыванием) и снова ждать, пока датчик снова станет низким (падающий фронт). Я реализовал это с помощью millis(), но код, похоже, не работает последовательно, так как время, кажется, пошло на бросок (случайное поведение; иногда он продолжает работать непрерывно, а иногда останавливается). Может ли кто-нибудь на этом форуме просмотреть его и предложить мне исправление. Кроме того, можно ли для этого использовать триггер LOW вместо заднего фронта?

#include <LowPower.h>


const int out1 = 5; //двигатель
const int IRSensor = 3; // подключаем инфракрасный датчик к контакту 6 Arduino
const int LED = 6; // подключаем светодиод к контакту 9 Arduino
const int Switch = 2;
const int Mspeed = 175;//0-255
const int Mtime =1500;//500-1000
int statusSensor=1;
int switchSensor=1;
unsigned long prevTime;
volatile int count =0;
volatile int count1=0;
volatile int count2 =0;
volatile int count3=0;
volatile int buttonstate=0;
volatile int lastbuttonstate=0;
volatile bool flag=false;

void setup() {
  // поместите сюда код установки для однократного запуска:
  Serial.begin(9600); 
  pinMode(out1,OUTPUT);
  //pinMode(out1,OUTPUT);
  pinMode (IRSensor, INPUT); // вывод датчика INPUT
  pinMode (LED, OUTPUT); // Светодиодный вывод ВЫХОД
  pinMode(Switch, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(IRSensor),IRinterrupt,FALLING);
}


void loop() {
  // поместите сюда ваш основной код для многократного запуска:
  LowPower.powerDown(SLEEP_FOREVER , ADC_OFF, BOD_OFF); 
  delay (100);
  if (flag==true){
  //Serial.println("true");
  switchSensor = digitalRead (Switch);
  //Serial.println("zloop");

  statusSensor = digitalRead (IRSensor);
  //Serial.println(statusSensor);
  if (count1==1) 
  { prevTime = millis();
    Serial.println(prevTime);
  }
  if (millis() - prevTime >= 1000) 
  { doSomethingElse();
    Serial.println("going to else");
  }
  }
  //prevState = digitalRead(IRSensor);
  doSomething();



}

void IRinterrupt(){

   flag=true;
  }

void doSomething(){
  buttonstatus();
  if (statusSensor == 0 and switchSensor == 0 and count3==0){

     analogWrite(out1,Mspeed);
     // цифровая запись (out1, HIGH);
     count1=count++;
     Serial.println(count);
     digitalWrite(LED, LOW);
  }
   else if (statusSensor == 0 and switchSensor == 1) {

      // цифровая запись (out1, LOW);
      digitalWrite(LED, HIGH);
      analogWrite(out1,0);
      count=0;
      count1=0;
      prevTime = millis();
      }
   else if (statusSensor == 1 and switchSensor == 0) {

      // цифровая запись (out1, LOW);
      digitalWrite(LED, LOW);
      analogWrite(out1,0);
      count=0;
      count1=0;
      prevTime = millis();
      }
    else {
      //Serial.println("высокий уровень");
      // цифровая запись (out1, LOW);
      digitalWrite(LED, HIGH);
      analogWrite(out1,0);
      count=0;
      count1=0;
      prevTime = millis();
      buttonstatus();
      }
} 
void doSomethingElse(){


      //Serial.println("ir high else");
      analogWrite(out1,0);
      count=0;
      count1=0;
      prevTime = millis();
      count2++;
      count3=count2;

      // аналоговая запись (out1,0);
  }

void buttonstatus(){
  buttonstate=digitalRead (IRSensor);
   if (buttonstate != lastbuttonstate) {
    // если состояние изменилось,
    if (buttonstate == LOW) {
      count3=0;
    }
    delay(50);
   }
   lastbuttonstate = buttonstate;
}

Я написал еще один фрагмент кода без прерываний. Как мне добиться такой же временной части и для этого?

int out1 = 5; //двигатель
int IRSensor = 3; // подключаем инфракрасный датчик к контакту 6 Arduino
int LED = 6; // подключаем светодиод к контакту 9 Arduino
int Switch = 2;
int statusSensor=1;
int switchSensor=1;


void setup() {
  // поместите сюда код установки для однократного запуска:
  Serial.begin(9600);
  pinMode(out1,OUTPUT);
  //pinMode(out1,OUTPUT);
  pinMode (IRSensor, INPUT); // вывод датчика INPUT
  pinMode (LED, OUTPUT); // Светодиодный вывод ВЫХОД
  pinMode(Switch, INPUT_PULLUP);
}

void loop() {
  // поместите сюда ваш основной код для многократного запуска:
  switchSensor = digitalRead (Switch);
  //Serial.println(SwitchSensor);

  statusSensor = digitalRead (IRSensor);
  //Serial.println(statusSensor);
  delayStart = millis();
  //Serial.println("с прерыванием");

   if (statusSensor == 0 and switchSensor == 0){
     Serial.println ("ir low");
     analogWrite(out1,120);
     digitalWrite(LED, LOW);
   }
      else {
      Serial.println ("ir high");
      analogWrite(out1,0);

      }

}

EDIT: теперь я успешно реализовал код (без прерываний) с временной частью в приведенном ниже коде. Кроме того, я обновил первый код в сообщении с прерываниями, но я не могу заставить работать временную часть. Может кто-нибудь, пожалуйста, помогите мне, как теперь можно сделать синхронизацию с прерываниями, чтобы arduino nano находился в спящем режиме, пока не получит задний фронт на выводе прерывания от ИК-датчика, чтобы он мог обработать следующую часть. Я считаю, что при этом я сэкономлю электроэнергию, так как она постоянно включена.

const int out1 = 5; //двигатель
const int IRSensor = 3; // подключаем инфракрасный датчик к контакту 6 Arduino
const int LED = 6; // подключаем светодиод к контакту 9 Arduino
const int Switch = 2;
const int Mspeed = 175;//0-255
const int Mtime =1500;//500-1000
int statusSensor=1;
int switchSensor=1;
unsigned long prevTime;
volatile int count =0;
volatile int count1=0;
volatile int count2 =0;
volatile int count3=0;
volatile int buttonstate=0;
volatile int lastbuttonstate=0;


void setup() {
  // поместите сюда код установки для однократного запуска:
  Serial.begin(9600); 
  pinMode(out1,OUTPUT);
  pinMode (IRSensor, INPUT); // вывод датчика INPUT
  pinMode (LED, OUTPUT); // Светодиодный вывод ВЫХОД
  pinMode(Switch, INPUT_PULLUP);
}


void loop() {
  // поместите сюда ваш основной код для многократного запуска:
  delay(100);
  switchSensor = digitalRead (Switch);
  statusSensor = digitalRead (IRSensor);
  if (count1==1) 
  { prevTime = millis();
    Serial.println(prevTime);
  }
  if (millis() - prevTime >= Mtime) 
  { doSomethingElse();
    //Serial.println("идем к другому");
  }
  doSomething();

}

void doSomething(){
  buttonstatus();
  if (statusSensor == 0 and switchSensor == 0 and count3==0){

     analogWrite(out1,Mspeed);
     // цифровая запись (out1, HIGH);
     count1=count++;
     Serial.println(count);
     digitalWrite(LED, LOW);
  }
   else if (statusSensor == 0 and switchSensor == 1) {

      // цифровая запись (out1, LOW);
      digitalWrite(LED, HIGH);
      analogWrite(out1,0);
      count=0;
      count1=0;
      prevTime = millis();
      }
   else if (statusSensor == 1 and switchSensor == 0) {

      // цифровая запись (out1, LOW);
      digitalWrite(LED, LOW);
      analogWrite(out1,0);
      count=0;
      count1=0;
      prevTime = millis();
      }
    else {
      //Serial.println("высокий уровень");
      // цифровая запись (out1, LOW);
      digitalWrite(LED, HIGH);
      analogWrite(out1,0);
      count=0;
      count1=0;
      prevTime = millis();
      buttonstatus();
      }
} 
void doSomethingElse(){


      //Serial.println("ir high else");
      analogWrite(out1,0);
      count=0;
      count1=0;
      prevTime = millis();
      count2++;
      count3=count2;

      // аналоговая запись (out1,0);
  }

void buttonstatus(){
  buttonstate=digitalRead (IRSensor);
   if (buttonstate != lastbuttonstate) {
    // если состояние изменилось,
    if (buttonstate == LOW) {
      count3=0;
    }
    delay(50);
   }
   lastbuttonstate = buttonstate;
}

, 👍-1

Обсуждение

Комментарии не для расширенного обсуждения; этот разговор был [перенесен в чат](https://chat.stackexchange.com/rooms/108619/discussion-on-question-by-user3796354-running-a-motor-for-a-3-seconds-continuous) ., @VE7JRO


2 ответа


0

Я часто использую цикл таймера для считывания показаний датчиков. Я приложил код, который компилируется, но датчика у меня нет.

Кстати. Я предполагаю, что это однократный ИК-датчик, который возвращает 0, если что-то обнаружено.

int out1 = 5; //двигатель
int IRSensor = 3; // подключаем инфракрасный датчик к контакту 6 Arduino
int LED = 6; // подключаем светодиод к контакту 9 Arduino
int Switch = 2;
int statusSensor=1;
int switchSensor=1;


unsigned long IRMillis;
int IRInterval = 100;

void setup() {
  // поместите сюда код установки для однократного запуска:
  Serial.begin(9600);
  pinMode(out1,OUTPUT);
  //pinMode(out1,OUTPUT);
  pinMode (IRSensor, INPUT); // вывод датчика INPUT
  pinMode (LED, OUTPUT); // Светодиодный вывод ВЫХОД
  pinMode(Switch, INPUT_PULLUP);
  IRMillis = millis();
}

void loop() {

   updateIR();

   switchSensor = digitalRead (Switch);

   if ((statusSensor == 0) && (switchSensor == 0)) {
     IRInterval = 3000; // 3 секунды
     statusSensor = 1;
     Serial.println ("ir low");
     analogWrite(out1,120);
     digitalWrite(LED, LOW);
   } else {
     Serial.println ("ir high");
     analogWrite(out1,0);
   }
}

void updateIR() {
  if (millis() - IRMillis > IRInterval) {
    //продолжать
  } else {
    return;
  }
  IRMillis = millis();
  IRInterval = 100;
  statusSensor = digitalRead (IRSensor);
} 
,

Да, возвращает 0., @user3796354


0

Ваш код прерывания выглядит разумным, за исключением того, что, установив для флага значение true, вы больше никогда не вернете его обратно в значение false. Вам нужен способ определить, что ИК-датчик больше не активен.

Возможно, изменить ваше прерывание, чтобы оно срабатывало при изменении состояния, и установить флаг в значение true, когда оно переключается в LOW (как будто нет), и в false, когда оно переключается обратно в состояние high? Мне нужно больше узнать о вашем ИК-датчике, чтобы точно сказать вам, что делать, но я могу сказать вам, что ваш код в настоящее время записывается, как только вы обнаружите первый спадающий фронт на выводе IRSensor, ваш флаг переключится на true и никогда не менять обратно на false.

Я также не понимаю, что должна делать вся логика if/else if/else if, поэтому не могу точно сказать, есть ли у вас какие-либо ошибки в коде.

,

Я использую ИК-датчик, который отключается только при обнаружении препятствия. Существует также поплавковый выключатель (датчик переключения), который, когда он поднимается (бак пустой), должен выключаться и включать светодиод. Вот почему существует несколько операторов if else. Тот же код без части прерывания (флажка) работает нормально, при этом двигатель останавливается, если он непрерывно работает в течение 1,5 секунд. Но с прерыванием временная часть не работает., @user3796354

Опять же, ваш код устанавливает flag=true в коде прерывания, но никогда не устанавливает flag=false. Это не правильно., @Duncan C