Управление L298n прерываниями

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

Ребята, у вас есть идея, как я могу использовать прерывания с драйвером двигателя L298n для перемещения моих двигателей постоянного тока вперед и назад.

Вот мой код

int fIR=7;
int bIR=8;
int fIR_value;
int bIR_value;      
const int trigPin = 9;
const int echoPin = 11;

long duration;
int distance;

int IN1 = 4;
int IN2 = 5;
int IN3 = 6;
int IN4 = 12;

void setup() {
  Serial.begin(9600);
  pinMode(fIR,INPUT);
  pinMode(fIR,INPUT);
  pinMode(trigPin,OUTPUT);
  pinMode(echoPin,INPUT);
  pinMode(IN1,OUTPUT);
  pinMode(IN2,OUTPUT);
  pinMode(IN3,OUTPUT);
  pinMode(IN4,OUTPUT);


}

void loop() {

  fIR_value = digitalRead(fIR);
  Serial.print("Front IR:");
  Serial.print(fIR_value);
  Serial.print(" , ");

  bIR_value = digitalRead(bIR);
  Serial.print("Back IR:");
  Serial.print(bIR_value);
  Serial.print(" , ");

  digitalWrite(trigPin, LOW);
  delayMicroseconds(10);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);  
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  distance = duration*0.034/2;
  Serial.print("Distance: ");
  Serial.println(distance);
  delay (500);

  if(distance<30&&fIR_value==HIGH&&bIR_value==LOW){
    STOP();
    delay(50);
    BACKWARD(); 
// Serial.print("1");
  }
  else if(distance<30&&fIR_value==LOW&&bIR_value==HIGH){
    STOP();
    delay(50);
    FORWARD();
// Serial.print("2");

  }
  else if(distance<30&&fIR_value==LOW&&bIR_value==LOW){
    STOP();
    delay(50);
    FORWARD();
// Serial.print("3");

  }
    else if(distance>30&&fIR_value==LOW&&bIR_value==LOW){
    STOP();
    delay(50);
    ROTATE();
// Serial.print("4");

  }
   else if(distance>30&&fIR_value==HIGH&&bIR_value==LOW){
    STOP();
    delay(50);
    BACKWARD();
// Serial.print("5");

  }
   else if(distance>30&&fIR_value==LOW&&bIR_value==HIGH){
    STOP();
    delay(50);
    FORWARD();
// Serial.print("6");

  }
}

void FORWARD(){

  digitalWrite(IN1,200);
  digitalWrite(IN2,0);
  digitalWrite(IN3,0);
  digitalWrite(IN4,200);
}
void BACKWARD(){

  digitalWrite(IN1,0);
  digitalWrite(IN2,200);
  digitalWrite(IN3,200);
  digitalWrite(IN4,0);
}
void ROTATE(){

  digitalWrite(IN1,200);
  digitalWrite(IN2,0);
  digitalWrite(IN3,200);
  digitalWrite(IN4,0);
}
void STOP(){

  digitalWrite(IN1,0);
  digitalWrite(IN2,0);
  digitalWrite(IN3,0);
  digitalWrite(IN4,0);
}

, 👍1

Обсуждение

вы не думаете, что вы должны использовать прерывания для датчиков?, @jsotola

если бы вы не использовали прерывания с датчиками, то что было бы источником прерываний от L298n?, @jsotola

О, это умно, @Saba Jayyusi

Как я могу написать вам DM .. Я новичок в этом, @Saba Jayyusi

научитесь использовать прерывание на одном контакте... используйте прерывание с одним датчиком, чтобы зажечь светодиод, @jsotola

Да, я пробовал это. Я пытался подключить светодиод с двумя кнопками., @Saba Jayyusi

Я воспользуюсь прерываниями с датчиками и сообщу вам результат. Спасибо., @Saba Jayyusi


1 ответ


1

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

Вместо этого вы можете использовать прерывания для своих датчиков.

Хотя я бы сказал, что использование прерываний на самом деле не нужно, когда вы правильно реализуете свой код, что означает неблокировку. Вы используете много вызовов delay(). где Arduino ничего не делает, просто вертит пальцами. Вместо этого вы можете использовать принцип из примера BlinkWithoutDelay, поставляемого с Arduino IDE, для написания неблокирующего кода. В этом случае каждый бит кода будет делать что-то только в случае необходимости, а в противном случае возвращаться быстро. Это ускорит работу вашего кода. Вам также необходимо установить меньшее время ожидания для функции pulseIn(), так как его стандартное время ожидания составляет 1 с (ультразвуковые датчики, которые вы используете, обычно могут обнаруживать только до 3 м, что будет соответствовать 20 мс). максимальная длительность импульса, если я правильно вычисляю).

Если использование прерываний является обязательной частью вашего упражнения, вы можете решить, где использовать прерывания:

  • Проще всего использовать ИК-датчики. Вы можете использовать функцию attachInterrupt() для настройки процедуры обработки прерываний (ISR) для соответствующего вывода. Если вы хотите, чтобы прерывание срабатывало, когда ИК-датчики становятся ВЫСОКИМ, вы можете использовать RISING, в противном случае вы можете использовать FALLING. Имейте в виду, что ISR должны быть как можно меньше и быстрее. Вы не можете использовать здесь delay(). Обычно в ISR устанавливают только простые (1 байт) переменные, а затем реагируют более длинными действиями в основном коде, проверяя эти переменные. Вы установили каждую переменную, которую можно изменить в ISR, как изменчивую:

    volatile byte flag;
    
  • Что касается ультразвукового датчика, у вас есть несколько способов. Я обозначу 2 способа. Для обоих из них вам нужно либо напрямую манипулировать регистрами специальных функций микроконтроллера, либо найти библиотеку, которая сделает это за вас (не знаю, существуют ли такие библиотеки, но вы можете найти их):

    1. Можно использовать прерывание смены контакта. Он срабатывает каждый раз, когда пин из полного пин-порта (группа до 8 пинов) меняет свое состояние. Вы можете замаскировать неиспользуемые выводы, чтобы они не влияли на прерывание. В ISR можно проверить состояние пина. Если он высокий, только что произошло начало импульса. Сохраните временную метку этого момента с помощью функции micros(). Следующий ISR (где контакт будет НИЗКИМ) отметит конец импульса. Теперь вы можете рассчитать разницу во времени между отметкой времени и текущим значением micros(). Вы должны использовать 1-байтовую переменную в качестве флага, чтобы запустить обработку длительности импульса в основной функции (или, если вы хотите напрямую использовать переменную разницы во времени, вам нужно включить прерывание, пока вы используете переменная).

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

,

См. здесь в https://github.com/delta-G/RobotLibs/blob/master/PingTimer.h и https://github.com/delta-G/RobotLibs/blob/master/PingTimer.cpp пример используя метод захвата прерывания для ультразвука (2-й метод выше), @Delta_G