Arduino Uno Buzzer/LED случайным образом перестает работать

Я работаю над школьным проектом Arduino, который использует ультразвуковой датчик в качестве детектора движения для срабатывания сигнализации. Датчик управляет 3 светодиодами и зуммером. На больших расстояниях загорается зеленый светодиод, на средних-синий, а на близких-красный. Петля устанавливается как для изменения интенсивности красного светодиода, так и для частоты зуммера. Я провел некоторое исследование и обнаружил, что использование tone() и SerialWrite() может вызвать проблемы, в зависимости от используемых контактов, поэтому я попытался найти способ обойти это. Не сработало.

Все работает нормально, когда я обновляю Arduino своим кодом, но после отключения датчика (чтобы активировать красный светодиод и зуммер) код, кажется, случайным образом ломается. После (случайного?) Количества успешных срабатываний сигнализации код, кажется, начинает пропускать затемнение красного светодиода, а также звук зуммера.

Я работаю с Arduino UNO (бренд Kuman), игнорирую модель, которую я случайно включил в схему.

В итоге я деконструировал множество функций и циклов в своем коде, чтобы попытаться решить возникшую проблему; например, я все еще отключил пользовательскую функцию alert (), но добавил ее вручную в код. Оба метода дали одинаковые результаты. В то время как зуммер и диммер не продолжают функционировать, все остальное продолжает работать нормально.

EDIT: я добавил задержку 100 мс в конец кода (после LedControl ()), чтобы легче контролировать последовательный выход. Оказывается, когда происходит ошибка, код, кажется, пропускает все задержки, и последовательный вывод снова становится очень быстрым.

EDIT 2: Когда возникает ошибка, последовательный вывод, кажется, сдвигается почти так же, как "D" и "istance:" разделяются, и часть остается в буфере до тех пор, пока не будет напечатана следующая строка. Если я нажму clear output и возьму фрагмент текста, он будет выглядеть так:

istance: 46
Distance: 45
Distance: 46
Distance: 46
Distance: 46
Distance: 47
Distance: 47
D

circuit sketch

// defines pins numbers
const int spkPin = 5;
const int echoPin = 8;
const int trigPin = 9;
const int rPin = 10;
const int bPin = 12;
const int gPin = 13;

// defines variables
long duration;
int distance;

void setup() {
pinMode(spkPin, INPUT);
pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
pinMode(echoPin, INPUT); // Sets the echoPin as an Input
pinMode(rPin, OUTPUT);
pinMode(bPin, OUTPUT);
pinMode(gPin, OUTPUT);
Serial.begin(9600); // Starts the serial communication
}

// dim LED over 7 * 255 ms
void alert(int led){
    for (int i=255; i>0; i--){
    analogWrite(led, i);
    tone(spkPin, 500+((255-i)*3) ,7); // increases frequency over time
    delay(7);
    noTone(spkPin);
  }
  
}

void ledControl(){
    if (distance >= 35){
      digitalWrite(rPin,LOW);
      digitalWrite(bPin,LOW);
      digitalWrite(gPin, HIGH);
      delay(50);
    }
  
  if (distance > 15 & distance < 35) {
    digitalWrite(rPin,LOW);
    digitalWrite(bPin,HIGH);
    digitalWrite(gPin, LOW);
    delay(50);
  }
  
  if (distance <= 15){
    digitalWrite(gPin, LOW);
    digitalWrite(bPin, LOW);
    
    //digitalWrite(rPin, HIGH);
    //alert(rPin);
    for (int i=255; i>0; i--){
      analogWrite(rPin, i);
      tone(spkPin, 500+((255-i)*3) ,7); // increases frequency over time
      delay(7);
      noTone(spkPin);
    }
    
    digitalWrite(rPin, LOW);
    
    delay(300);
    
    //digitalWrite(rPin, HIGH);
    //alert(rPin);
     for (int i=255; i>0; i--){
      analogWrite(rPin, i);
      tone(spkPin, 500+((255-i)*3) ,7); // increases frequency over time
      delay(7);
      noTone(spkPin);
    }

    digitalWrite(rPin, LOW);
   
    delay(300);
    
    //digitalWrite(rPin, HIGH);
    //alert(rPin);
    for (int i=255; i>0; i--){
      analogWrite(rPin, i);
      tone(spkPin, 500+((255-i)*3) ,7); // increases frequency over time
      delay(7);
      noTone(spkPin);
     }
    
    digitalWrite(rPin, LOW);
    
    delay(300);
  }
}

void loop() {

  // Clears the trigPin
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  // Sets the trigPin on HIGH state for 10 micro seconds
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  // Reads the echoPin, returns the sound wave travel time in microseconds
  duration = pulseIn(echoPin, HIGH);
  // Calculating the distance
  distance= duration*0.034/2;
  // Prints the distance on the Serial Monitor
  Serial.print("Distance: ");
  Serial.println(distance);
  ledControl();
}

Вот фрагмент из последовательного вывода, который перестал работать в точке с пометкой "(HERE)". Как ни странно, расстояние, на котором ничто не блокирует датчик, изменяется с 995~ до 1000~.

Distance: 996
Distance: 995
Distance: 995
Distance: 995
Distance: 995
Distance: 14
Distance: 996
Distance: 995
Distance: 995
Distance: 995
Distance: 995
Distance: 995
Distance: 11 
Distance: 996
Distance: 995
Distance: 995
Distance: 35
Distance: 38
Distance: 31
Distance: 35
Distance: 32
Distance: 28
Distance: 28
Distance: 995
Distance: 151
Distance: 1001 (HERE)
Distance: 24
Distance: 25
Distance: 24
Distance: 22
Distance: 22
Distance: 22
Distance: 21
Distance: 22
Distance: 21
Distance: 21
Distance: 20
Distance: 20
Distance: 20
Distance: 20
Distance: 20
Distance: 20
Distance: 20
Distance: 20
Distance: 20
Distance: 20
Distance: 20
Distance: 20
Distance: 19
Distance: 19
Distance: 19
Distance: 19
Distance: 19
Distance: 18
Distance: 19
Distance: 19
Distance: 19
Distance: 19
Distance: 19
Distance: 19
Distance: 19
Distance: 19
Distance: 18
Distance: 18
Distance: 18
Distance: 17
Distance: 16
Distance: 16
Distance: 16
Distance: 17
Distance: 16
Distance: 15
Distance: 12
Distance: 8
Distance: 8
Distance: 1000
Distance: 1000
Distance: 1000
Distance: 1000
Distance: 1000
Distance: 1000
Distance: 406
Distance: 408
Distance: 1000
Distance: 1000
Distance: 1000
Distance: 1000
Distance: 1000
Distance: 1000


, 👍0

Обсуждение

Не могли бы вы добавить несколько серийных отпечатков для отладки? Это может помочь найти проблему при наблюдении за тем, что все еще печатается. Эти последовательные отпечатки не мешают функции tone (), так как они выполняются независимо различными аппаратными средствами., @chrisl

@chrisl Я просто возился с ним в течение 15 минут подряд, наблюдая за последовательным выходом, и не могу найти ничего странного. Я опубликую фрагмент в правке., @Nick

Я имел в виду, что вы должны добавить больше серийных отпечатков в свой код, чтобы отметить выполнение каждой части. Например, выполняйте последовательную печать всякий раз, когда вы запускаете цикл сигнализации и всякий раз, когда вы его покидаете (непосредственно перед и после соответствующего цикла for). Распылите такие серийные отпечатки по всему вашему коду, а затем проверьте, входит ли код в соответствующие части кода. Таким образом, вы можете увидеть, связана ли проблема с кодом, данными датчика или с выходной электроникой. особенно проверьте, звучит ли сигнал тревоги, когда расстояние становится меньше 15 метров., @chrisl

Предназначен для генерации тонального сигнала на ВХОДНОМ выводе?, @KIIV

Я пробовал переключаться между ВХОДОМ и ВЫХОДОМ, но это не имеет значения., @Nick

@Nick для более чистого кода используйте if (distance >= 35) {} ... else if (расстояние > 15 ) {} ... еще {}, @jsotola

многие/большинство зуммеров используют слишком большой ток для питания от GPIO. Он может работать некоторое время, пока тепловая защита не отключит его или микроконтроллер просто не выйдет из строя., @dandavis


1 ответ


0

Ник,

Строка 42: if (distance > 15 & distance < 35) использует побитовый оператор &. Вам нужно логическое and (&&) вот так: if (distance > 15 && distance < 35). То, как вы это сделаете, скорее всего, помешает ему запустить этот раздел.

Кроме того, у вас есть настройка spkPin в качестве входного сигнала, но вы пытаетесь сгенерировать на нем тон. Я считаю, что вам нужно изменить это на вывод. pinMode(spkPin, ВХОД); --> pinMode(spkPin, ВЫХОД);

Я переписал этот код таким образом, чтобы очистить некоторые вещи. Я проверил это (я просто установил расстояние равным разным расстояниям), чтобы проверить все состояния, и это работает чудесно. Я кое - что объясню. Во-первых, смотрите!

// defines pins numbers
const int spkPin = 5;
const int echoPin = 8;
const int trigPin = 9;
const int rPin = 10;
const int bPin = 12;
const int gPin = 13;

// defines variables
long duration = 0;
int distance = 0;
int state = 0; 

void setup() {
pinMode(spkPin, INPUT); // I think you mean output here
pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
pinMode(echoPin, INPUT); // Sets the echoPin as an Input
pinMode(rPin, OUTPUT);
pinMode(bPin, OUTPUT);
pinMode(gPin, OUTPUT);
Serial.begin(9600); // Starts the serial communication
}

// dim LED over 7 * 255 ms
void alert(int led){
    for (int i=255; i>0; i--){
    analogWrite(led, i);
    tone(spkPin, 500+((255-i)*3) ,7); // increases frequency over time
    delay(7);
    noTone(spkPin);
  }
  
}
void loop() {
  
  getDistance(); // self explanatory 
  
  /*  state machine setup
   *  Level 1 is above 35"
   *  Level 2 is between 15 and 35"
   *  Level 3 is below 15"
   */
  if (distance >= 35)                 { state = 1; } 
  if (distance > 15 && distance < 35) { state = 2; }
  if (distance <= 15)                 { state = 3; }

  switch (state) {
    case 1: // long distance
      Serial.println("Case 1, we made it!");
      digitalWrite(rPin,LOW);
      digitalWrite(bPin,LOW);
      digitalWrite(gPin, HIGH);
      delay(50);
    break;
    
    case 2: // medium distance
      Serial.println("Case 2, we made it!");
      digitalWrite(rPin,LOW);
      digitalWrite(bPin,HIGH);
      digitalWrite(gPin, LOW);
      delay(50);
    break;
    
    case 3: // short distance
      Serial.println("Case 3, we made it!");
      digitalWrite(gPin, LOW);
      digitalWrite(bPin, LOW);
      //digitalWrite(rPin, HIGH);
      //alert(rPin);
      
      for (int i = 0; i < 3; i++)
        {
          for (int i=255; i>0; i--) {
            analogWrite(rPin, i);
            tone(spkPin, 500+((255-i)*3) ,7); // increases frequency over time
            delay(7);
            noTone(spkPin);
           } // frequency loop
          
          digitalWrite(rPin, LOW);    
          delay(300);    
          //digitalWrite(rPin, HIGH);
          //alert(rPin);          
          
        } //3x for loop
        
    break;
    
    default: // if the state doesn't match any of 
             // the cases perform these actions below.
    digitalWrite(gPin, LOW);
    digitalWrite(bPin, LOW);
    digitalWrite(rPin, LOW);
    break;
    
  } // switch state close bracket
  
} // void loop

void getDistance()
{
  // Clears the trigPin
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  // Sets the trigPin on HIGH state for 10 micro seconds
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  // Reads the echoPin, returns the sound wave travel time in microseconds
  duration = pulseIn(echoPin, HIGH, 2000); // add timeout to pulse
  // Calculating the distance
  distance = duration*0.034/2;
  // Prints the distance on the Serial Monitor
  Serial.print("Distance: ");
  Serial.println(distance);
}

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

Затем мы настраиваем наши операторы if, которые определяют, в какое состояние мы собираемся перейти. Теперь все ваши утверждения if находятся в одном удобном месте.

Здесь мы будем использовать переключатель и корпус для выполнения ваших различных функций. Вы можете увидеть, как работает эта функция, перейдя на страницу обучения Arduino. Вы можете видеть, что в разных случаях я ставлю Serial.println("Случай 1 мы сделали это здесь!"); это просто очень простой способ отслеживания того, где в коде вы находитесь для целей отладки. Если вы застряли, вы всегда можете поставить серийные отпечатки в тех местах, где вы это сделали.

Последнее, что нужно объяснить, это то, что я понял, что в вашем цикле кратчайшего расстояния код повторяется 3 раза подряд. Есть более простой способ сделать это! Вы можете просто вложить свой код в цикл for следующим образом: for (int i = 0; i < 3; i++ {yourcodehere} и все здесь будет работать 3 раза. Вы можете видеть, как я сделал это в случае 3:.

Вы также должны быть осторожны с использованием задержек. Вы должны заглянуть в blink без задержки (другими словами, умное использование таймеров для ожидания определенного количества времени без использования функции задержки, которая приостанавливает все действия на arduino и эффективно "замораживает" его.

Вот и все! Дайте мне знать, если это хорошо работает и если у вас есть какие-либо вопросы.

,

Спасибо, что помогли мне сделать код более кратким, и было приятно узнать, как кейсы работают с arduino; однако ваш код приводит к тому же результату. Все светодиоды работают нормально, как и зуммер, но после случайного количества срабатываний сигнализации он перестает работать. Есть ли контрольный знак того, что таймер перестал работать должным образом, или способ сбросить их?, @Nick

Было бы полезно, если бы я добавил видео, отображающее его правильное поведение и поведение, которое он демонстрирует, когда он ломается?, @Nick

Черт! Что происходит в последовательном мониторе? Где он застрял? Добавьте несколько серийных отпечатков, чтобы узнать, @HavocRC

Я добавил отладки в каждую часть кода, все по-прежнему выполняется, и все отладки отображаются на последовательном мониторе. Разница лишь в том, что задержки полностью пропущены, как если бы таймер перестал работать, без задержки зуммер и диммер фактически ничего не сделают, потому что они сработают мгновенно. Что-то происходит, чтобы код игнорировал или не мог обрабатывать задержки., @Nick

Ник, я почти уверен, что нашел эту проблему. Попробуйте установить тайм-аут для pulseIn. После прочтения некоторых сообщений кажется, что он может повесить трубку и сбросить Arduino, если он не сможет получить импульс. Попробуйте установить тайм-аут в 2000 мс и посмотреть, исправит ли это что-нибудь. pulseIn(pin, value, timeout), @HavocRC

Установка тайм-аута на 2000 мс приводит к полному сбою; расстояние постоянно возвращается как 0; кажется, что 5000ms работает, но только так же хорошо, как и отсутствие тайм-аута вообще. Как еще одно уточнение: когда он выходит из строя, он все еще технически читает все правильно, и светодиоды реагируют правильно. Но он начинает игнорировать задержки, поэтому зуммер издает только небольшой звук "поп", а красная лампочка мигает 3 раза. (вместо того чтобы медленно тускнеть). Я попробую установить его на 50000ms и позволить ему работать., @Nick

Именно этот сценарий звучит как электрическая неисправность. Удачи тебе, парень, @HavocRC