HC-SR04 измерение расстояния без задержки?

Я использую ультразвуковой датчик HC-SR04 для Arduino. Я использовал следующий код для расчета расстояния, и он отлично работает.

  long duration;
  digitalWrite(trigger, LOW);  
  delayMicroseconds(2);
  digitalWrite(trigger, HIGH);
  delayMicroseconds(10); 
  digitalWrite(trigger, LOW);
  duration = pulseIn(echo, HIGH);
  distance = (duration/2) / 29.1;

Однако я хочу использовать еще три таких датчика, всего четыре. Этот блок кода будет вызываться каждый раз, когда я захочу найти расстояние до одного из датчиков. Однако меня беспокоит, что delayMicroseconds() приостанавливает всю программу и что я не могу выполнять другие задачи, пока работают датчики (например, водить колеса, это робот). Следующий код является объектно-ориентированным для каждого датчика.

class distSensor{
   int trigPin;
   int echoPin;
   int distance;

   //Будет использоваться в таймере
   unsigned long previousMillis;

   public:
   distSensor(int tPin,int ePin){
   trigPin = tPin;
   echoPin = ePin;

   pinMode(trigPin, OUTPUT);
   pinMode(echoPin, INPUT);

   previousMillis = 0;
 }

 int calculateDistance(){

  // записывает время с момента запуска программы
  unsigned long currentMillis = millis();

  long duration;
  digitalWrite(trigPin, LOW); 

  //проверить, превышает ли предыдущий раз, когда вызывался метод, интервал 2
  if(currentMillis - previousMillis > 2){
    digitalWrite(trigPin, HIGH);
    previousMillis = currentMillis;
  }

  //проверить, превышает ли расстояние между текущим временем и временем предыдущего вызова интервал 10.
  if(currentMillis - previousMillis > 10){
      digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  distance = (duration/2) / 29.1;
  }
  return distance;
 }
};

В методе calculateDistance() я пытаюсь сделать то же самое, что и в первом коде, но без delay(), а вместо этого с таймером. Но когда я запускаю программу, она не работает, и расстояние читается как 0. Может ли кто-нибудь помочь мне переписать код HC-SR04 с самого начала, чтобы не задерживать всю программу?

, 👍2

Обсуждение

Попытка использовать несколько звуковых датчиков расстояния одновременно может быть проблематичной. Если они должны «слышать» друг друга, их работа может привести к неожиданным значениям. Рассмотрите возможность использования оптических датчиков расстояния, основанных на принципе параллакса., @st2000

они смотрят перпендикулярно и в противоположных направлениях, это не проблема, @Don Grey

Вероятно, существуют конфигурации (углы комнаты), которые все еще могут сбивать с толку содарные и сонарные датчики, пытающиеся взять пробы одновременно., @st2000

pulseIn() тоже блокирует, так что это не поможет; вам нужно прерывание., @dandavis

Вы сказали, что прочитанное расстояние равно 0 ; ваш код не работает, потому что вы запускаете датчик с задержками 2 мс и 10 мс, вы должны использовать delayMicroseconds 2us и 10us. Поскольку эти задержки есть в нас, вам не нужно их избегать, вы можете использовать delayMicroseconds в своих кодах. Функция pulseIn() блокируется слишком долго, это то, чего вам следует избегать с помощью прерывания, как сказал Дандавис., @Arno Bozo


3 ответа


2

delay() заставляет процессор ничего не делать, кроме ожидания. Вам нужно переключиться на millis().

В вашем коде вам нужно "схватить" текущее время с помощью millis() и сохранить его в переменной. Добавьте к этой переменной количество миллисекунд, которое вы хотите ждать — вам придется рассмотреть случай, когда это значение будет переполнено для полного решения. Затем в вашем коде вам нужно создать бесконечный цикл, в котором вы проверяете, что возвращает millis(). Когда ваше сохраненное значение и millis() совпадают, пришло время выполнить код, который обычно следует после вызова delay().

Здесь, Игровая площадка Arduino — как и почему избежать задержки(), delay() и millis() подробно обсуждаются.

Чтобы этот ответ охватил ваш вопрос, подумайте о том, чтобы поместить все ваши события, которые должны быть рассчитаны по времени, в этот бесконечный цикл. Кроме того, рекомендуется использовать независимые переменные, по одной для каждого синхронизированного события, чтобы разные события синхронизировались независимо друг от друга.

,

//проверить, превышает ли предыдущий раз, когда вызывался метод, интервал 2 если (текущий Миллис - предыдущий Миллис > 2) { digitalWrite(trigPin, ВЫСОКИЙ); предыдущий Миллис = текущий Миллис; } //проверить, превышает ли расстояние между текущим временем и временем предыдущего вызова интервал 10. если (текущий Миллис - предыдущий Миллис > 10) { digitalWrite(trigPin, LOW); продолжительность = pulseIn(echoPin, HIGH); расстояние = (длительность/2)/29,1; } Я уже сделал это, но это все еще не работает. currentmillis — время, отсчитываемое от запуска программы,, @Don Grey

Комментарий очень тяжело читать. Вам нужно учитывать переполнение используемого типа переменной и типа, возвращаемого вызовом medthod к millis(). Я не думаю, что вы включили это в свой комментарий выше. Кроме того, из-за того, как вы описываете события, вам, возможно, придется беспокоиться об использовании целых чисел без знака. Может быть проще проверить, возвращает ли millis() ожидаемое значение, чем искать разницу между тем, что возвращает millis(), и некоторой переменной., @st2000


1
enter code here
#define ECHO 5        // Пин получил эхо-импульс
#define TRIGGER 6     // Пин посылает импульс выстрела

int distance; // расстояние в см
unsigned long previousMicros = 0; // будем считать, что последний раз TRIGGER обновлялся
long OnTime = 10; //микросекунды времени включения
long OffTime = 2; //микросекунды простоя
unsigned long previousMillis = 0; //сохранит время последнего обновления viewTime
int triggerState = LOW; // triggerState, используемый для его настройки
long duration;   
void setup()    
{   
  Serial.begin(9600);   
  pinMode(ECHO, INPUT);   
  pinMode(TRIGGER, OUTPUT);     
}    

void loop()   
{   
  // проверяем, не пора ли изменить состояние ТРИГГЕРА
  unsigned long currentMicros = micros();     
  if((triggerState == LOW) && (currentMicros - previousMicros >= OffTime))     
   {      
     triggerState = HIGH; // включить его
     previousMicros = currentMicros; // запоминаем время
     digitalWrite(TRIGGER, triggerState); // обновить фактический триггер
   }    
   else if((triggerState == HIGH) && (currentMicros - previousMicros >= OnTime))    
   {           
     triggerState = LOW; // выключи
     previousMicros = currentMicros; // запоминаем время
     digitalWrite(TRIGGER, triggerState); // обновить фактический триггер
   }    



duration = pulseIn(ECHO,HIGH  );      
Serial.println(distance);        
distance = ((duration*0.034)/2);       
Serial.print("distance: ");        

}

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

,

0
unsigned long currentMillis = micros();
digitalWrite(Trig, LOW);

if (currentMillis - previousMillis > 4) {
  digitalWrite(Trig, HIGH);
  previousMillis = currentMillis;
}

if (currentMillis - previousMillis > 12) {
  digitalWrite(Trig, LOW);
  previousMillis = currentMillis;
}

impulseTime = pulseIn(Echo, HIGH);
distance_sm = impulseTime / 58; // конвертируем в сантиметры
distance = distance_sm;
,