Нужна помощь с функцией

sirius1
Offline
Зарегистрирован: 17.03.2016

Добрый день.

Идея в следующем. Через Serial отправляю номер пина на ардуино, должен загореться диод на этом пине, при повторном - выключится. Тестится все для пина 13. Собственно, не срабатывает ledX=!ledX при вызове функции, т.е. на экране все время "Led 13 is on". Как исправить.

Заранее благодарен))

boolean ledA = LOW;

void switchPin(boolean ledX,int  i)
{
  if(ledX == LOW)
    {
    Serial.print("Led ");
    Serial.print(i);
    Serial.println(" is on");
    digitalWrite(i, HIGH);
  ledX=!ledX; // не срабатывает
    }
  else
    {
      Serial.print("Led ");
      Serial.print(i);
      Serial.println(" is off");
      digitalWrite(i, LOW);
  ledX=!ledX;
    }
}
void setup() {
  pinMode(10,OUTPUT);
  pinMode(11,OUTPUT);
  pinMode(12,OUTPUT);
  pinMode(13,OUTPUT);
  Serial.begin(9600);
}

void loop() {
  while (Serial.available()==0);
  int val = Serial.read() - '0';
  Serial.println(val);
 
  if(val>9&&val<14) //проверяем число
  {
  switchPin(ledA,val); //вызываем функцию
 }
  else
  {
    Serial.println("Error. Try again");
    }
    Serial.flush();
 }

Araris
Offline
Зарегистрирован: 09.11.2012

Строку ledX=!ledX; замените на ledA=!ledA;

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Araris пишет:

Строку ledX=!ledX; замените на ledA=!ledA;

Почему? У него ж ledX - параметр функции, а Вы предлагаете к глобальную переменную менять - некрасиво. Пусть лучше вернёт значение и присвоит его ledA

sirius1
Offline
Зарегистрирован: 17.03.2016

ммм.. а если я немного переделаю? добавлю еще лампочек? Меня интересует как через функцию меня параметр ledA, так как при каждой отправке на COM порт числа и прокрутке функции, ledA всегда видится как LOW

boolean ledA = LOW;

boolean ledB = LOW;

if(val = 12) //проверяем число
  {
  switchPin(ledA,val); //вызываем функцию
 }

if(val = 13) //проверяем число
  {
  switchPin(ledB,val); //вызываем функцию
 }

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

sirius1,

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

Вот я хочу Вам что-то объяснить, но для объяснений мне нужно ссылаться на номера строк. А где они у Вас? Как мне ссылаться?

Учитывая, что Вы здесь первый день, а я сегодня добрый, я сделаю это за Вас, но впредь так не делайте. 

Итак, вот Ваш код.

boolean ledA = LOW;

void switchPin(boolean ledX, int  i)
{
  if (ledX == LOW)
  {
    Serial.print("Led ");
    Serial.print(i);
    Serial.println(" is on");
    digitalWrite(i, HIGH);
    ledX = !ledX; // не срабатывает
  }
  else
  {
    Serial.print("Led ");
    Serial.print(i);
    Serial.println(" is off");
    digitalWrite(i, LOW);
    ledX = !ledX;
  }
}
void setup() {
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(13, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  while (Serial.available() == 0);
  int val = Serial.read() - '0';
  Serial.println(val);

  if (val > 9 && val < 14) //проверяем число
  {
    switchPin(ledA, val); //вызываем функцию
  }
  else
  {
    Serial.println("Error. Try again");
  }
  Serial.flush();
}

Всё там у Вас отлично срабатывает, переменная ledX внутри функции меняется. Но Вы, очевидно, ожидаете. что будет заодно меняться и переменная ledA, которая передавалась как параметр. А вот это фигушки! С какого перепугу? Вы ведь её передаёте по значению! Другими словами, Вы передаёте в функцию вычисленное значение переменной ledA а не её саму. Внутри функции Вы можете с этим значением делать что угодно, но снаружи (на самой ledA) это никак не отразится. Что Вы и наблюдаете.

Вариантов как это поправить - 100500. 

Самый простой (но далеко не самый лучший) - передавать в функцию не значение ledA, а ссылку на неё. Тогда функция благополучно изменит ledA, т.к. она имеет дело не с вычисленным значением, а со ссылкой на оригинальную переменную. Для того, чтобы ledA передавалась по ссылке достатчно в строке 3 добавить один символ.

void switchPin(boolean ledX, int  i) // Сейчас так
void switchPin(boolean & ledX, int  i) // А надо так

и будет Вам счастье. Попробуйте.

Да, и кстати, для чего у Вас делаются одинаковые действия в обеих ветвях if'а? Я имею в виду строки 11 и 19. Незачем дублировать дважды одно и то же. Обе эти строки надо убрать, а вставить одну такую же после строки 20. Будет всё тоже самое, но стилистически правильнее.

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

Более идеологочисеки кошерный способ - сделать это через возвращаемое значение.

Для этого

1. В строке 3 заменяем void на boolean (теперь функция будет возвращать значение)
2. Строки 11 и 19 выбрасываем.
3. Между строками 20 и 21 вставляем возврат значения: return ! ledX
4. В строку 37 добавляем приём возвращённого значения. Должно получиться:

 ledA = switchPin(ledA, val); //вызываем функцию

И всё должно заработать.

И последнее. Если уж делать совсем по уму, надо перенести строку 1 внутрь функции loop. Нефиг этой переменной быть глобальной - к тому нет никаких причин.

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

sirius1 пишет:

ммм.. а если я немного переделаю? добавлю еще лампочек? 

Любым из описанных мною способов будет работать на любое количество лампочек.

sirius1
Offline
Зарегистрирован: 17.03.2016

Ok. Спасибо больше. Все встало на свои места.

Кстати, по поводу переноса переменной в loop. Не работает)) Может я конечно ее как-то не так переношу, но если оставить ее на строке 1 - все ок

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

static boolean ledA = LOW;

или boolean ledA ;   

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

sirius1 пишет:

Кстати, по поводу переноса переменной в loop. Не работает)) 

Должно работать. Когда возникают такие вопросы, не ленитесь вставить код. чтобы было видно как именно Вы её перенесли, а то так, вслепую, что можно сказать?

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Внутри loop только если static, иначе работать не будет

sirius1
Offline
Зарегистрирован: 17.03.2016

Собственно вставляю код. С параметром static у переменной все работает... в каких либо других вариантах - нет - ledA всегда в LOW.

boolean switchPin(boolean ledX,int  i)
{
  if(ledX == LOW)
    {
    Serial.print("Led ");
    Serial.print(i);
    Serial.println(" is on");
    digitalWrite(i, HIGH);  
    }
  else
    {
      Serial.print("Led ");
      Serial.print(i);
      Serial.println(" is off");
      digitalWrite(i, LOW);
    }
    return !ledX;
}
void setup() {
  pinMode(10,OUTPUT);
  pinMode(11,OUTPUT);
  pinMode(12,OUTPUT);
  pinMode(13,OUTPUT);
  Serial.begin(9600);
}
void loop() {
  boolean ledA = LOW;
  while (Serial.available()==0);
  int val = Serial.read() - '0';
  Serial.println(val);
  val=val+9;
  if(val>9&&val<14)
  {
  ledA = switchPin(ledA,val);
  }
  else
  {
    Serial.println("Error. Try again");
    }
    Serial.flush();
 }

а static я так понимаю переменная только внутри функции? т.е. за пределами loop я ее не увижу?

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

первым оператором цикла, в строке 27, ты присваиваешь ledA LOW, и удивляешься, что она всегда LOW.

Ты странный?

И верно, переменная с модификатором static инициализируется один раз, при первом вызове,, поэтому оно у тебя и работало в таком виде.

оставь так (со "статиком") - сойдет. "Гуру" может и поругают, но работать будет.

В "хорошем" стиле, неважно объектный или процедурный С используем, переменные с текущим состоянием неких предметов (лампочек) - прячем внутрь класса (или функции, тогда они там "static") и наружу оставляем только "хвостки" интерфейсов к ним.

Есть еще подход чисто процедурного С - заводим структуру со всеми признаками и состояниями, и указатель на нее передаем по всем нужным функциям. Так написано 90% ядра Linux. Выбирай сам, если - непонятно - придется курить учебник по программированию.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, разумеется, static.

А снаружи, нет, не увидите. Для того и заносили внутрь.