Использование оператора case с приемником ИК-излучателя

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

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

В итоге я ищу три модуля, которые будут загораться случайным образом, когда один загорается, он ждет, пока что-то не сломает луч, затем загорается другой и ждет... У кого-нибудь есть идеи, как заставить это работать?

int ledselect;
int led1 = 2;
int led2 = 3;
int ir1 = 4;
int ir2 = 5;
int s1 = A0;
int s2 = A1;

void setup() {
  Serial.begin(9600);
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(ir1, OUTPUT);
  pinMode(ir2, OUTPUT);
  pinMode(s1, INPUT);
  pinMode(s2, INPUT);

}
void loop() {
  ledselect = random(2);
  switch (ledselect) {

    case 0:
      digitalWrite(led1, HIGH);
      digitalWrite(ir1, HIGH);
      delay(50);
      while (analogRead(s1) >= 100)
      {
        delay(50);
        digitalWrite(led1, LOW);
        digitalWrite(ir1, LOW);
      }
      break;

    case 1:
      digitalWrite(led2, HIGH);
      digitalWrite(ir2, HIGH);
      delay(50);
      while (analogRead(s2) >= 100)
      {
        delay(50);
        digitalWrite(led2, LOW);
        digitalWrite(ir2, LOW);
      }
      break;
  }
}

, 👍-1

Обсуждение

скетч не будет продолжаться до тех пор, пока случай не будет удовлетворен... это не совсем правильно... оператор case - это просто структура решения, которая разветвляется на разные части кода в зависимости от значения параметра.. .. это похоже на серию операторов if, @jsotola


1 ответ


0

Происходит следующее:

  1. Выбирается случайное число
  2. Горит свет
  3. Он срабатывает, когда рядом ничего нет (при условии, что низкое значение аналогового датчика означает, что поблизости ничего нет?)
  4. Горит тот же или другой индикатор (в зависимости от случайного светодиода).
  5. Продолжить с 3.

Некоторые причины, по которым это может не сработать:

  • Проверьте значение (должно ли оно быть больше или меньше 100?)
  • Возможно, датчик не очень точен и иногда дает 0 или максимальные значения, которые неверны. Чтобы изменить это, несколько раз прочитайте датчик и возьмите среднее значение или удалите несколько самых низких и самых высоких значений (чтобы удалить пики) и получите среднее значение.

ОБНОВЛЕНИЕ

Тело операторов case почти одинаково, сделайте его функцией, вызываемой из обоих операторов case:

Ваш код будет выглядеть так:

void loop() {
  ledselect = random(2);
  switch (ledselect) {
    case 0:
      process(led1, ir1, s1);
      break;

    case 1:
      process(led2, ir2, s2);
      break;
  }
}

void process(int led, int sw, int ir)
{
  digitalWrite(led, HIGH);
  digitalWrite(ir, HIGH);
  delay(50);
  while (analogRead(sw) >= 100)
  {
    delay(50);
    digitalWrite(led, LOW);
    digitalWrite(ir, LOW);
  }
}

Если вы используете тернарный оператор ( x ? y : z, что означает, если x чем y else z), то ваша функция loop будет выглядеть так:

void loop() {
  ledselect = random(2);
  process(ledselect == 0 ? led1 : led2, 
          ledselect == 0 ?  ir1 :  ir2,
          ledselect == 0 ?   s1 :   s2);
}

Еще более элегантный способ — использовать массив для частей (не знаю, какое имя может быть лучше), вместо всех переменных с именами 0 и 1, поместить их в массивы, и вы получите следующий код ниже. Если вы сделаете больше деталей, вы просто измените начало кода.

int ledselect;

const int NrOfParts = 2;

int leds     [NrOfParts] = {  2 , 3 };
int irs      [NrOfParts] = {  4,  5 };
int switches [NrOfParts] = { A0, A1 };

void setup() {
  Serial.begin(9600);
  for (int part = 0; part < NrOfParts; part++)
  {
    pinMode(leds    [part], OUTPUT);
    pinMode(irs     [part], OUTPUT);
    pinMode(switches[part],  INPUT);
  }
}

void loop() 
{
  ledselect = random(2);
  process(leds[ledselect], irs[ledselect], switches[ledselect]);
}

void process(int led, int sw, int ir)
{
  digitalWrite(led, HIGH);
  digitalWrite(ir, HIGH);
  delay(50);
  while (analogRead(sw) >= 100)
  {
    delay(50);
    digitalWrite(led, LOW);
    digitalWrite(ir, LOW);
  }
}

Обновление 2

Еще лучший способ — создать структуру (так вы будете хранить всю информацию об одной "части" вместе).

Это решение использует & (разыменование), что означает, что это похоже на переменную, указывающую на часть.

int ledselect;

const int NrOfParts = 2;

struct Part
{
  int led;
  int ir;
  int sw;
};

Part _parts[NrOfParts] = 
{
  { 2, 4, A0 }, 
  { 3, 5, A1 } 
};

void setup() {
  Serial.begin(9600);
  for (int partNumber = 0; partNumber < NrOfParts; partNumber++)
  {
    Part& part = _parts[partNumber];
    pinMode(part.led, OUTPUT);
    pinMode(part.ir , OUTPUT);
    pinMode(part.sw ,  INPUT);
  }
}

void loop() 
{
  process(_parts[random(2)]);
}

void process(Part& part)
{
  digitalWrite(part.led, HIGH);
  digitalWrite(part.ir, HIGH);
  delay(50);
  while (analogRead(part.sw) >= 100)
  {
    delay(50);
    digitalWrite(part.led, LOW);
    digitalWrite(part.ir, LOW);
  }
}
,

Спасибо, Мишель, за ваш ответ. Я воспользовался вашим предложением, чтобы очистить скетч, и очень ценю, что вы нашли время, чтобы проанализировать мой вопрос и ответ., @Bender

Я добавил еще несколько альтернатив, не используйте их, если вы не чувствуете себя комфортно., @Michel Keijzers