Многозадачность в Arduino с использованием функции millis () - PullRequest
0 голосов
/ 21 апреля 2020

Я подумываю о том, чтобы построить автомобиль типа "самодельный гокарт-внедорожник" из металлолома. А в качестве электроники я планирую использовать Arduino Uno для управления практически всем. Итак, я только что сделал показ передач, который позволяет мне узнать, на каком устройстве я сейчас работаю. И простой датчик парковки.

Если я слишком близко к объекту, зуммер датчика парковки будет мигать. И я не могу мигать с функциями delay (), потому что, если я попытаюсь сместиться вверх, когда он мигает, вход не будет зарегистрирован, потому что задержка является функцией блокировки. Поэтому я попытался использовать миллис вместо этого, но, похоже, он также не регистрируется.

Концепция проста. У меня будет две кнопки на каждой стороне моего переключения. И когда я сдвигаюсь вверх, кнопка нажимается, поэтому 7-сегментный дисплей добавляет один. И еще один для понижающей передачи.

Я еще не добавил передачу заднего хода, но все еще, когда функция датчика парковки работает, я все еще не могу нажимать sh кнопки в течение длительного времени.

Надеюсь, вы, ребята, поняли, что я пытаюсь сказать. Я только начал программировать в Arduino, поэтому у меня не хватает опыта. Я оставляю файл .ino как блок кода. Я пытался объяснить все в коде. Надеюсь, кто-то знает решение для этого. Заранее спасибо ...



// Setting up the pins for 7-Segment-Display.
const int E = 13;
const int D = 12;
const int C = 11;
const int DP = 10;
const int G = 9;
const int F = 8;
const int A = 7;
const int B = 6;


// Setting up the counter for gear shifting.

int gearCount = 0;

// Setting up the button states and button pin for state-change detectors.

int buttonAddPin = 5;
int buttonAddState = 0;
int previousButtonAddState = 0;

// And this is for downshifting.

int buttonSubstractPin = 4;
int buttonSubstractState = 0;
int previousButtonSubstractState = 0;


// Adding buzzer for parking sensor.

const int buzzerPin = 3;
int buzzerTone = 0;


// Adding parking sensor.

const int trigPin = 2;
const int echoPin = 1;
long duration;
int distance;


// Adding non-delay blinker with millis for buzzer to blink when sensor detects an object.

unsigned long previousTime = 0;




/*---------------------------------- FUNCTIONS FOR SHIFTING -------------------------------------------------*/


// "zero" function is the series of commands for displayıng 0 on the 7-Segment corresponding to neutral gear.

void zero()
{
  digitalWrite(A, LOW);
  digitalWrite(B, LOW);
  digitalWrite(C, LOW);
  digitalWrite(D, LOW);
  digitalWrite(E, LOW);
  digitalWrite(F, LOW);
  digitalWrite(G, HIGH);
  digitalWrite(DP, HIGH);

}


// "one" function is the series of commands for displaying 1 on the 7-Segment-Display corresponding to 1st gear.

void one()
{
  digitalWrite(A, HIGH);
  digitalWrite(B, LOW);
  digitalWrite(C, LOW);
  digitalWrite(D, HIGH);
  digitalWrite(E, HIGH);
  digitalWrite(F, HIGH);
  digitalWrite(G, HIGH);
  digitalWrite(DP, HIGH);

}


// "two" function is the series of commands for displaying 2 on the 7-Segment-Display corresponding to 2nd gear.

void two()
{
  digitalWrite(A, LOW);
  digitalWrite(B, LOW);
  digitalWrite(C, HIGH);
  digitalWrite(D, LOW);
  digitalWrite(E, LOW);
  digitalWrite(F, HIGH);
  digitalWrite(G, LOW);
  digitalWrite(DP, HIGH);
}



// "three" function is the series of commands for displaying 3 on the 7-Segment-Display corresponding to 3rd gear.

void three()
{
  digitalWrite(A, LOW);
  digitalWrite(B, LOW);
  digitalWrite(C, LOW);
  digitalWrite(D, LOW);
  digitalWrite(E, HIGH);
  digitalWrite(F, HIGH);
  digitalWrite(G, LOW);
  digitalWrite(DP, HIGH);
}


// And now the main function that we are going to call in "void loop" to determine which gear we are on.

void gearDisplay()
{

  buttonAddState = digitalRead(buttonAddPin);          // And now the button state change detector for shifting up is ready. As you can see when I push the button
                                                       // program adds 1 to gearCount variable. So now gearCount is 1. Therefore the 7-Segment-Display will show
  if(buttonAddState != previousButtonAddState){        // 1 on it. We will do this a bit later.

    if(buttonAddState == HIGH){
      gearCount++;
    }

   delay(50);

  }

  previousButtonAddState = buttonAddState;


// Now for downshifting.


  buttonSubstractState = digitalRead(buttonSubstractPin);

  if(buttonSubstractState != previousButtonSubstractState) {

     if(buttonSubstractState == HIGH){
        gearCount--;
     }

  delay(50);


  }

  previousButtonSubstractState = buttonSubstractState;



// Now we will call one of the 7-Segment-Display number functions according to the gearCount variable.


  if(gearCount == 0){
    zero();
  }

  else if(gearCount == 1){
    one();
  }


  else if(gearCount == 2){
    two();
  }


  else if(gearCount == 3){
    three();
  }


  else if(gearCount > 3){                 // Just making sure if we press buttons accidentally more than enough, it sets gearCount back to closest gear available.
    gearCount--;
  }


  else if(gearCount < 0){                 // Same with this one.
    gearCount++;
  }

}


// That was al for the gear panel. Now the hard part. The parking sensor.


/*---------------------------------------------- SHIFTING DONE ----------------------------------------------------*/












/*--------------------------------------------- PARKING SENSOR ------------------------------------------------------*/



void parkingSensor()
{

  digitalWrite(trigPin, LOW);                 // Resetting trigPin

  delayMicroseconds(2);                       // Delaying to prevent any issiues. ( I saw this online, most people do it like this so I also did.)


  digitalWrite(trigPin, HIGH);                // Creating a short soundwave.
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  duration = pulseIn(echoPin, HIGH);          // Detecting the time that passes for the soundwave to reach back to the receiver.

  distance = duration*0.034/2;                // Simple math for calculating the distance between the obstacle and sensor.


  unsigned long currentTime = millis();       // Store the current time for blinking the buzzers.


  if((distance > 0) && (distance < 31)){              // If the distance is in between 0-31 buzz non-stop.

    buzzerTone = 1000;
    tone(buzzerPin, buzzerTone);
  }


  else if((distance > 30) && (distance < 76)){        // If the distance is between 30-76 buzz every 100 miliseconds.

      if(currentTime - previousTime >= 100){

        previousTime = currentTime;

        if(buzzerTone == 1000){

          buzzerTone = 0;
        }

        else {

          buzzerTone = 1000;
        }

       tone(buzzerPin, buzzerTone);
      }
  }


  else if((distance > 75) && (distance < 101)){      // If the distance is between 75-101 buzz every 300 miliseconds.

      if(currentTime - previousTime >= 300){

        previousTime = currentTime;


          if(buzzerTone == 1000){

            buzzerTone = 0;
          }

          else {

           buzzerTone = 1000;
          }

       tone(buzzerPin, buzzerTone);

      }
  }



  else if(distance > 100){                         // If the distance is more than 100 don't buzz.

    buzzerTone = 0;

    tone(buzzerPin, buzzerTone);
  }

}

/*------------------------------- PARKING SENSOR DONE -----------------------------------*/




// And this was, I guess, all I had to do but unfortunately it's not working...



void setup() {


  pinMode(A, OUTPUT);
  pinMode(B, OUTPUT);
  pinMode(C, OUTPUT);
  pinMode(D, OUTPUT);
  pinMode(E, OUTPUT);
  pinMode(F, OUTPUT);
  pinMode(G, OUTPUT);
  pinMode(DP, OUTPUT);
  pinMode(buttonAddPin, INPUT);
  pinMode(buttonSubstractPin, INPUT);
  pinMode(buzzerPin, OUTPUT);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
}

void loop() {

  gearDisplay();

  parkingSensor();
}

РЕДАКТИРОВАТЬ : Оказывается, что длительность pulseIn() по умолчанию составляет 1 секунду. И это также функция блокировки, которая блокирует кнопки от регистрации входов на каждом l oop в течение 1 секунды. Изменение этого значения на меньшее, например, 10 мс в моем случае, было достаточным и решило проблему. Вся заслуга принадлежит @CherryDT, который решил это. Большое спасибо.

Кстати, вот как должен выглядеть код в течение 10 мс: pulseIn(echoPin, HIGH, 10000)

// Обратите внимание, что длительность в pulseIn() указана в микросекундах.

1 Ответ

0 голосов
/ 21 апреля 2020

РЕДАКТИРОВАТЬ: Оказывается, я неправильно понял вопрос. В любом случае, оставив этот ответ здесь, потому что он отвечает «как мигать без блокировки», что также может быть полезно.

Ответ на главную проблему будет таким: Вы используете pulseIn, который также блокирует, пока импульс не будет получил. Время ожидания по умолчанию для pulseIn составляет одну секунду, поэтому, если ваш датчик парковки не видит никаких объектов, вы блокируете на 1 с каждый раз! Так как вы, вероятно, в любом случае интересуетесь достаточно небольшими расстояниями, вы можете просто установить тайм-аут, скажем, 10 мс (10000 мкс):

pulseIn(echoPin, HIGH, 10000)

Если это не соответствует вашим требованиям или все еще слишком много задержка, однако, попробуйте написать свой собственный код, который измеряет время без блокировки, обрабатывая нажатия кнопок в это время. См. этот ответ , где кто-то имел точно такую ​​же проблему и решил ее таким образом.

По сути, вы могли бы сделать что-то вроде этого:

unsigned long pulseTimer = 0;
int lastEchoState = HIGH; // Initially HIGH so that the actual LOW triggers a "change"

void loop () {
  int currentEchoState = digitalRead(echoPin);

  // To set a timeout of the pulse, simulate a pulse if already waiting for too long
  if (lastEchoState == LOW && micros() - pulseTimer > 1000000ul) {
    currentEchoState = HIGH;
  }

  if (currentEchoState != lastEchoState) {
    lastEchoState = currentEchoState;
    if (currentEchoState == LOW) {
      // Echo pulse over (or it's the initial loop iteration)

      // Start counting time until echo
      // We do this before sending the trigger because pulseIn would
      // normally measure until the pulse is *over*, but for simplicity
      // we measure until the pulse *starts*, so this implicitly shifts
      // the result by our pulse duration, as trigger and echo pulse are
      // usually of the same length
      pulseTimer = micros();

      // Send new trigger pulse
      delayMicroseconds(2);
      digitalWrite(trigPin, HIGH);
      delayMicroseconds(10);
      digitalWrite(trigPin, LOW);
    } else {
      // Pulse came in, measure time
      unsigned long pulseDelayTime = micros() - pulseTimer;

      // **** DO SOMETHING WITH pulseDelayTime HERE! ****
    }
  }

  // **** DO YOUR REGULAR BUTTON PROCESSING HERE! ****
}

Вы будет мигать, если установить светодиодный выход:

(millis() / 500) % 2

... чтобы мигать на каждой l oop итерации *.

Это будет в основном НИЗКОЕ для 500 мс и ВЫСОКИЙ на 500 мс, потому что деление millis() на 500 (которое не будет иметь дробной части, потому что мы здесь в целочисленном мире) даст число, которое увеличивается каждые 500 мс, а % 2 принимает его по модулю 2, т.е. быть 1 для нечетных и 0 для четных чисел. И 1 и 0 такие же, как HIGH и LOW для Arduino.

Пример:


+----------+--------------+------------------+
| millis() | millis()/500 | (millis()/500)%2 |
+----------+--------------+------------------+
|      ... |              |                  |
|     1499 |            2 |         0 (LOW)  |
|     1500 |            3 |         1 (HIGH) |
|     1501 |            3 |         1 (HIGH) |
|      ... |              |                  |
|     1999 |            3 |         1 (HIGH) |
|     2000 |            4 |         0 (LOW)  |
|     2001 |            4 |         0 (LOW)  |
|      ... |              |                  |
|     2499 |            4 |         0 (LOW)  |
|     2500 |            5 |         1 (HIGH) |
|     2501 |            5 |         1 (HIGH) |
|      ... |              |                  |
+----------+--------------+------------------+

Классный проект, кстати.

*: Если вы хотите увеличить производительность, вы можете сохранить последнее состояние вывода в отдельной переменной и делать digitalWrite только после его изменения. Это потому, что digitalWrite на самом деле довольно медленный, поэтому вы можете не называть его каждый раз, если не требуется фактическое изменение.

...