Смена частоты моргания диодом по нажатию кнопки

Женёк
Offline
Зарегистрирован: 21.12.2015

Всем привет!

Купил себе стартовый набор Ардуино, чтобы играться, самому и с дочерью :) Опыта в программировании нет никакого вообще (BASIC в 7 классе не в счёт), но не гуманитарий, так что осваиваюсь. Собственно вопрос: написал программу, хочу чтобы она моргала светодиодом с частотой 10 Гц, при однократном нажатии кнопки переходила на частоту 2 Гц, по следующему нажатию выключала диод, и опять по кругу. Вот листинг:

int GREEN1 = 3; //контакт 3 для светодиода
int BUTTON = 2; //контакт 2 для кнопки
boolean lastButton = LOW; //переменная для хранения последнего состояния кнопки
boolean currentButton = LOW; //переменная для хранения текущего статуса кнопки
int lmode = 0; //переменная для статуса светодиода
void setup()
{
  pinMode (GREEN1, OUTPUT); //устанавливаем пин3 как выход
  pinMode (BUTTON, INPUT); //устанавливаем пин2 как вход
}
boolean debounce(boolean last) //функция сглаживания, выдает значения HIGH или LOW
{
  boolean current = digitalRead(BUTTON); //считываем состояние кнопки
  if (last != current) //если не такое, как было
  {
    delay(10); //то ждём 10 мс
    current = digitalRead(BUTTON); //опять считываем состояние кнопки
    return current; //возвращаем состояние
  }
}
void setMode (int mode) //функция для выполнения моргания. void т.к. она ничего не вычисляет
{
  while (mode == 0) //если режим равен 0
  {
    digitalWrite (GREEN1, HIGH); //подаём питание
    delay (100); //держим 100 мс
    digitalWrite (GREEN1, LOW); //выключаем питание
    delay(100); //держим 100 мс
  }
  while (mode == 1); //если режим равен 1
  {
    digitalWrite (GREEN1, HIGH); //подаём питание
    delay (500); //держим 500 мс
    digitalWrite (GREEN1, LOW); //выключаем питание
    delay(500); //держим 500 мс
  }
  while (mode == 2); //если режим равен 1
  {
    digitalWrite (GREEN1, LOW); //выключаем питание
  }
}
void loop()
{
  currentButton = debounce(lastButton); //подаём функции debounce текущее состояние кнопки, по сути считываем состояние с учётом дребезга
  if (lastButton == LOW && currentButton == HIGH) //если кнопка нажата
  {
    lmode++;    //увеличиваем состояние счётчика режима на 1
  }
  lastButton = currentButton; //запоминаем последнее состояние кнопки
  if (lmode = 3) //если счётчик дошёл до значения 3, которое не предусмотрено в теле функции setMode
  lmode = 0; //то мы его обнуляем
  setMode (lmode); //и передаём значение функции setMode
}

По факту диод всегда моргает с частотой 10 Гц, и не реагирует на кнопку. Есть подозрение, что дело в реализации моргания с помощью delay(t) - выполнение программы прерывается, и обработки нажатия не происходит. Прав ли я?

Извините за глупый вопрос.

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014

Попробуйте так

int GREEN1 = 3; //контакт 3 для светодиода
int BUTTON = 2; //контакт 2 для кнопки
boolean lastButton = LOW; //переменная для хранения последнего состояния кнопки
boolean currentButton = LOW; //переменная для хранения текущего статуса кнопки
int lmode = 0; //переменная для статуса светодиода
void setup()
{
  pinMode (GREEN1, OUTPUT); //устанавливаем пин3 как выход
  pinMode (BUTTON, INPUT); //устанавливаем пин2 как вход
}
boolean debounce(boolean last) //функция сглаживания, выдает значения HIGH или LOW
{
  boolean current = digitalRead(BUTTON); //считываем состояние кнопки
  if (last != current) //если не такое, как было
  {
    delay(10); //то ждём 10 мс
    current = digitalRead(BUTTON); //опять считываем состояние кнопки
    return current; //возвращаем состояние
  }
}
void setMode (int mode) //функция для выполнения моргания. void т.к. она ничего не вычисляет
{
  if (mode == 0) //если режим равен 0
  {
    digitalWrite (GREEN1, HIGH); //подаём питание
    delay (100); //держим 100 мс
    digitalWrite (GREEN1, LOW); //выключаем питание
    delay(100); //держим 100 мс
  }
  if (mode == 1); //если режим равен 1
  {
    digitalWrite (GREEN1, HIGH); //подаём питание
    delay (500); //держим 500 мс
    digitalWrite (GREEN1, LOW); //выключаем питание
    delay(500); //держим 500 мс
  }
  if (mode == 2); //если режим равен 1
  {
    digitalWrite (GREEN1, LOW); //выключаем питание
  }
}
void loop()
{
  currentButton = debounce(lastButton); //подаём функции debounce текущее состояние кнопки, по сути считываем состояние с учётом дребезга
  if (lastButton == LOW && currentButton == HIGH) //если кнопка нажата
  {
    lmode++;    //увеличиваем состояние счётчика режима на 1
    lastButton = currentButton; //запоминаем последнее состояние кнопки
  }
  
  if (lmode = 3) //если счётчик дошёл до значения 3, которое не предусмотрено в теле функции setMode
  lmode = 0; //то мы его обнуляем
  setMode (lmode); //и передаём значение функции setMode
}

А также делай надо сменить на милис  

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

Женёк, при запуске скетча Вы попадаете в цикл while (mode == 0), который будет выполняться бесконечно (выхода из него нет), то есть до следующего перезапуска скетча.

Женёк
Offline
Зарегистрирован: 21.12.2015

vosara, cкопировал ваш код, скомпилировал и залил в плату. Диод моргает странно, два короткие вспышки (примерно по 100 мс как раз), потом пауза на полсекунды, и опять две вспышки. На кнопку не реагирует.

Araris, спасибо! То есть надо в конце каждого блока while считывать значение кнопки что ли?

vvadim
Offline
Зарегистрирован: 23.05.2012

вы бы вообще ушли от while

int GREEN1 = 3; //контакт 3 для светодиода
int BUTTON = 2; //контакт 2 для кнопки
boolean lastButton = LOW; //переменная для хранения последнего состояния кнопки
boolean currentButton = LOW; //переменная для хранения текущего статуса кнопки
int mode = 0; //переменная для статуса светодиода

void setup()
{
  pinMode (GREEN1, OUTPUT); //устанавливаем пин3 как выход
  pinMode (BUTTON, INPUT); //устанавливаем пин2 как вход
}
boolean debounce(boolean last) //функция сглаживания, выдает значения HIGH или LOW
{
  boolean current = digitalRead(BUTTON); //считываем состояние кнопки
  if (last != current) //если не такое, как было
  {
    delay(10); //то ждём 10 мс
    current = digitalRead(BUTTON); //опять считываем состояние кнопки
    return current; //возвращаем состояние
  }
}

void loop()
{
  currentButton = debounce(lastButton); //подаём функции debounce текущее состояние кнопки, по сути считываем состояние с учётом дребезга
  if (lastButton == LOW && currentButton == HIGH) //если кнопка нажата
  {
    mode++;    //увеличиваем состояние счётчика режима на 1
  }
  lastButton = currentButton; //запоминаем последнее состояние кнопки
  if (mode > 2) //если счётчик дошёл до значения 3, которое не предусмотрено в теле функции setMode
    mode = 0; //то мы его обнуляем

  if (mode == 0) //если режим равен 0
  {
    digitalWrite (GREEN1, HIGH); //подаём питание
    delay (100); //держим 100 мс
    digitalWrite (GREEN1, LOW); //выключаем питание
    delay(100); //держим 100 мс
  }
  else if (mode == 1) //если режим равен 1
  {
    digitalWrite (GREEN1, HIGH); //подаём питание
    delay (500); //держим 500 мс
    digitalWrite (GREEN1, LOW); //выключаем питание
    delay(500); //держим 500 мс
  }
  else if (mode == 2) //если режим равен 2
  {
    digitalWrite (GREEN1, LOW); //выключаем питание
  }
}

 

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014

Araris и vvadim правы надо уйти от while что я и сделал заменил while на if а кнопка не работает потому что строчку № 48 нужно вынести из if что я и сделал в прилагаемом коде Хотя проблема с делай осталась и кнопку нужно держать нажатой больше одной секунды. Я специально не переписываю Ваш код а только исправил чтобы вам было легче разобраться

int GREEN1 = 3; //контакт 3 для светодиода
int BUTTON = 2; //контакт 2 для кнопки
boolean lastButton = LOW; //переменная для хранения последнего состояния кнопки
boolean currentButton = LOW; //переменная для хранения текущего статуса кнопки
int lmode = 0; //переменная для статуса светодиода
void setup()
{
  pinMode (GREEN1, OUTPUT); //устанавливаем пин3 как выход
  pinMode (BUTTON, INPUT); //устанавливаем пин2 как вход
}
boolean debounce(boolean last) //функция сглаживания, выдает значения HIGH или LOW
{
  boolean current = digitalRead(BUTTON); //считываем состояние кнопки
  if (last != current) //если не такое, как было
  {
    delay(10); //то ждём 10 мс
    current = digitalRead(BUTTON); //опять считываем состояние кнопки
    return current; //возвращаем состояние
  }
}
void setMode (int mode) //функция для выполнения моргания. void т.к. она ничего не вычисляет
{
  if (mode == 0) //если режим равен 0
  {
    digitalWrite (GREEN1, HIGH); //подаём питание
    delay (100); //держим 100 мс
    digitalWrite (GREEN1, LOW); //выключаем питание
    delay(100); //держим 100 мс
  }
  if (mode == 1); //если режим равен 1
  {
    digitalWrite (GREEN1, HIGH); //подаём питание
    delay (500); //держим 500 мс
    digitalWrite (GREEN1, LOW); //выключаем питание
    delay(500); //держим 500 мс
  }
  if (mode == 2); //если режим равен 1
  {
    digitalWrite (GREEN1, LOW); //выключаем питание
  }
}
void loop()
{
  currentButton = debounce(lastButton); //подаём функции debounce текущее состояние кнопки, по сути считываем состояние с учётом дребезга
  if (lastButton == LOW && currentButton == HIGH) //если кнопка нажата
  {
    lmode++;    //увеличиваем состояние счётчика режима на 1
  }
  lastButton = currentButton; //запоминаем последнее состояние кнопки
  if (lmode = 3) //если счётчик дошёл до значения 3, которое не предусмотрено в теле функции setMode
  lmode = 0; //то мы его обнуляем
  setMode (lmode); //и передаём значение функции setMode
}

 

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

Delay() - долой !

Я мигание поместил бы прямо в loop(), примерно так :

int GREEN1 = 3; //контакт 3 для светодиода
int BUTTON = 2; //контакт 2 для кнопки
boolean lastButton = LOW; //переменная для хранения последнего состояния кнопки
boolean currentButton = LOW; //переменная для хранения текущего статуса кнопки
int lmode = 0; //переменная для режима светодиода
boolean greenState = LOW; //переменная состояния светодиода
unsigned int lastGreenStateChanged = 0; //время (millis()) последнего изменения состояния светодиода
void setup()
{
  pinMode (GREEN1, OUTPUT); //устанавливаем пин3 как выход
  pinMode (BUTTON, INPUT); //устанавливаем пин2 как вход
}
boolean debounce(boolean last) //функция сглаживания, выдает значения HIGH или LOW
{
  boolean current = digitalRead(BUTTON); //считываем состояние кнопки
  if (last != current) //если не такое, как было
  {
    delay(10); //то ждём 10 мс
    current = digitalRead(BUTTON); //опять считываем состояние кнопки
    return current; //возвращаем состояние
  }
}

void loop()
{
  currentButton = debounce(lastButton); //подаём функции debounce текущее состояние кнопки, по сути считываем состояние с учётом дребезга
  if (lastButton == LOW && currentButton == HIGH) //если кнопка нажата
  {
    lmode++;    //увеличиваем состояние счётчика режима на 1
  }
  lastButton = currentButton; //запоминаем последнее состояние кнопки
  if (lmode = 3) //если счётчик дошёл до значения 3, которое не предусмотрено в теле функции setMode
  lmode = 0; //то мы его обнуляем

  if ( (mode == 0) && (millis() - lastGreenStateChanged >= 100) ) // режим 0 и прошло уже 100 мсек с момента последнего изменения состояния светодиода ?
  {  greenState = !greenState;  lastGreenStateChanged = millis();  }
  else if ( (mode == 1) && (millis() - lastGreenStateChanged >= 500) ) // режим 1 и прошло уже 500 мсек с момента последнего изменения состояния светодиода ?
  {  greenState = !greenState;  lastGreenStateChanged = millis();  }
  else if (mode == 2) // режим 2 - выключаем питание
  {  greenState = LOW;  }
  digitalWrite (GREEN1, greenState); //выполняем
}

// Код из головы, простите, коли где ошибся.
Женёк
Offline
Зарегистрирован: 21.12.2015

vvadim, спасибо!

vosara, вы заменили внутри функции setMode(mode) все циклы while на if? Но я не понимаю, почему так работает :) Внутри конструкции if всё равно нет проверки состояния переменной mode, так же как у меня в while.

Я хочу написать функцию для моргания (чтобы вызывать её из функции setMode), вот код:

void Blink (unsigned long INTERVAL, int LED_PIN) //функция воспринимает интервал и пин вывода в качетсве входных параметров
{
  unsigned long Time = millis(); //записываем время работы контроллера
  if (Time - previousTime > INTERVAL) //если прошло достаточно времени, то
  {
    previousTime = Time; //перезаписываем время
    boolean LED_STATE; //вводим локальную переменную, хранящую состояние диода
    if (LED_STATE == LOW) //если диод выключен
      LED_STATE = HIGH; //то включаем его
    else //а иначе
      LED_STATE = LOW; //опять выключаем
    digitalWrite (LED_PIN, LED_STATE); //тут включаем/выключаем диод.
  }
}

Потом я вызываю эту функцию из setMode

void setMode (int mode) //функция для выполнения моргания. void т.к. она ничего не вычисляет
{
  if (mode == 0) //если режим равен 0
  {
    Blink (GREEN1, GREEN1_INTERVAL1); //моргаем на выводе GREEN1 с интервалом GREEN1_INTERVAL1
  }
  if (mode == 1); //если режим равен 1 
  {
    Blink (GREEN1, GREEN1_INTERVAL2);
  }
  if (mode == 2); //если режим равен 2
  {
    digitalWrite (GREEN1, LOW); //выключаем питание
  }
}

Но ничего не работает, диод не моргает, на кнопку не реагирует.

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014
Вы запускаете цыкл из которого нет выхода и он работает все време не выходя в loop() Вот он 
 
 while (mode == 0) //если режим равен 0
  {
    digitalWrite (GREEN1, HIGH); //подаём питание
    delay (100); //держим 100 мс
    digitalWrite (GREEN1, LOW); //выключаем питание
    delay(100); //держим 100 мс
  }
 
А когда Вы поставили if() Функция отработала один раз и вернулась в loop() а там идет проверка кнопки и потом снова в функцию
vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014

По поводу Вашего кода и желания. Хороший пример дал Araris просто модифицируйте его, если нужна функция возьмите код с 35 строки по 41 и вынесите отдельно. 

Женёк
Offline
Зарегистрирован: 21.12.2015

Кстати, ваш код из предыдущего комментария не работает :( Скопировал его с форума, залил на контроллер, диод дважды моргает быстро, потом пауза на полсекунды. На кнопку не реагирует.

Код Araris тоже не работает, по крайней мере если его взять и скопировать. Он даже не компилируется, т.к. переменная mode не объявлена.

То есть в цикле while возможно только внутреннее изменение условия, а в if() - внешнее? 

И есть мысли почему моя функция Blink() не работает? Вы поймите, если бы мне нужен был готовый результат, я бы пошёл в интернет и скачал готовые коды, библиотеки и т.п. Я разобраться хочу, что у меня не так.

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

Женёк пишет:

Код Araris тоже не работает, по крайней мере если его взять и скопировать. Он даже не компилируется, т.к. переменная mode не объявлена.

Виноват-с, в строках 35, 37, 39 поменяйте mode на lmode.

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014

Проверил в протеусе кнопка не работает по причине отсутствия подтягивающего резистора. Поставте и будет работать!!!

Женёк
Offline
Зарегистрирован: 21.12.2015

Всё равно не работает. Моргает 10 Гц, на кнопку не реагирует. Через некоторое время просто ровно горит.

Резистор стоит на землю, 10 кОм.

Всё-так подскажите кто знает, где у меня в функциях ошибка? Полный листинг

int GREEN1 = 3; //контакт 3 для светодиода
int BUTTON = 2; //контакт 2 для кнопки
boolean lastButton = LOW; //переменная для хранения последнего состояния кнопки
boolean currentButton = LOW; //переменная для хранения текущего статуса кнопки
int lmode = 0; //переменная для статуса светодиода
int GREEN1_INTERVAL1 = 100; //100 мс для моргания 10 Гц
int GREEN1_INTERVAL2 = 500; //500 мс для моргания 2 Гц
long previousTime = 0;
void setup()
{
  pinMode (GREEN1, OUTPUT); //устанавливаем пин3 как выход
  pinMode (BUTTON, INPUT); //устанавливаем пин2 как вход
}
boolean debounce(boolean last) //функция сглаживания, выдает значения HIGH или LOW
{
  boolean current = digitalRead(BUTTON); //считываем состояние кнопки
  if (last != current) //если не такое, как было
  {
    delay(10); //то ждём 10 мс
    current = digitalRead(BUTTON); //опять считываем состояние кнопки
    return current; //возвращаем состояние
  }
}
void setMode (int mode) //функция для выполнения моргания. void т.к. она ничего не вычисляет
{
  if (mode == 0) //если режим равен 0
  {
    Blink (GREEN1, GREEN1_INTERVAL1); //моргаем на выводе GREEN1 с интервалом GREEN1_INTERVAL1
  }
  if (mode == 1); //если режим равен 1 
  {
    Blink (GREEN1, GREEN1_INTERVAL2);
  }
  if (mode == 2); //если режим равен 2
  {
    digitalWrite (GREEN1, LOW); //выключаем питание
  }
}
void Blink (long INTERVAL, int LED_PIN) //функция воспринимает интервал и пин вывода в качетсве входных параметров
{
  long Time = millis(); //записываем время работы контроллера
  if (Time - previousTime > INTERVAL) //если прошло достаточно времени, то
  {
    previousTime = Time; //перезаписываем время
    boolean LED_STATE; //вводим локальную переменную, хранящую состояние диода
    if (LED_STATE == LOW) //если диод выключен
      LED_STATE = HIGH; //то включаем его
    else //а иначе
      LED_STATE = LOW; //опять выключаем
    digitalWrite (LED_PIN, LED_STATE); //тут включаем/выключаем диод.
  }
}
void loop()
{
  currentButton = debounce(lastButton); //подаём функции debounce текущее состояние кнопки, по сути считываем состояние с учётом дребезга
  if (lastButton == LOW && currentButton == HIGH) //если кнопка нажата
  {
    lmode++;    //увеличиваем состояние счётчика режима на 1
  }
  lastButton = currentButton; //запоминаем последнее состояние кнопки
  if (lmode = 3) //если счётчик дошёл до значения 3, которое не предусмотрено в теле функции setMode
  lmode = 0; //то мы его обнуляем
  setMode (lmode); //и передаём значение функции setMode
}

То есть я хочу иметь отдельную функцию debounce, которая обрабатывает нажатие кнопки, и возвращает текущее состояние. И отдельную функцию моргания, которая моргает указанным диодом с указанной частотой. Просто если я потом захочу добавить ещё 5 диодов с разной частотой моргания, то мне нужно будет всего лишь добавить 5 переменных для их контактов, 5 переменных для интервалов, и вызвать функцию Blink нужное количество раз.

P.S. Чтобы не было сомнений: вот схема соединений, для упрощения убрана монтажная плата. Схема рабочая, простейшая программа - зажечь диод при нажатой кнопке - на ней выполняется.

 

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

Сразу бросается в глаза - функция millis() возвращает unsigned long, а в скетче переменные previousTime и Time объявлены как long. С реагированием на кнопку это не связано, но лучше исправьте.

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

Ещё вопросы:

Что возвращает функция debounce(), если условие в 17-й строке не выполнилось ?

Для чего нужна строка 20 ?

Женёк
Offline
Зарегистрирован: 21.12.2015

Спасибо за замечание, но мне бы заставить программу работать, а вылизывать стиль можно и потом.

Ничего не выдаёт. А это надо в явном виде прописывать? В строке 20 мы меняем состояние переменной, хранящей состояние кнопки. То есть, если состояние кнопки изменилось, мы ждем 10 мс, ещё раз считываем его, и если оно за это время не изменилось, то мы считаем, что последнее измерение - правильное.

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

Сделайте временно 55-ю строку как currentButton = digitalRead(BUTTON);

Женёк
Offline
Зарегистрирован: 21.12.2015

Мистика какая-то! Не компилирует, на строке 01 выдаёт ошибку: 'int GREEN1' previously defined here

 

Перезапустил IDE, скомпилировалось. Замена на 

currentButton = digitalRead(BUTTON);

эффекта не дала, не работает!

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

OK, есть ещё один способ понять, что же происходит при работе скетча.

В setup() пропишите Serial.begin(9600); 

В интересующих местах выводите в монитор последовательного порта нужную информацию, например, после строки 58 вставьте Serial.print("lmode="); Serial.println(lmode);

Или, скажем, после строки 20 - Serial.print("current="); Serial.println(current);

Ну и тому подобное. Типа дебаггер.

Женёк
Offline
Зарегистрирован: 21.12.2015

Так, прошлое сообщение удалил, в нём смысла нет.

Рукотворный дебаггер говорит, вот что при однократном нажатии

current=1
current=0
 
То есть функция всегда выдаёт кнопка ВЫКЛ. Если держать кнопку зажатой появляется строка current=1, при отпускании тут же current=0
vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014

Вот Ваш рабочий код, Сравните с тем что Вы опубликовали и проанализуйте ошибки описывать не буду.

#define GREEN1 3 //контакт 3 для светодиода
#define BUTTON 2 //контакт 2 для кнопки
boolean lastButton = LOW; //переменная для хранения последнего состояния кнопки
boolean currentButton = LOW; //переменная для хранения текущего статуса кнопки
int lmode = 2; //переменная для статуса светодиода
int GREEN1_INTERVAL1 = 100; //100 мс для моргания 10 Гц
int GREEN1_INTERVAL2 = 500; //500 мс для моргания 2 Гц
unsigned long previousTime = 0;


void setup()
{
  pinMode (GREEN1, OUTPUT); //устанавливаем пин3 как выход
  pinMode (BUTTON, INPUT); //устанавливаем пин2 как вход
//Serial.begin(9600); 
}

boolean debounce(boolean last) //функция сглаживания, выдает значения HIGH или LOW
{
  boolean current = digitalRead(BUTTON); //считываем состояние кнопки
  if (last != current) //если не такое, как было
  {
    delay(10); //то ждём 10 мс
    current = digitalRead(BUTTON); //опять считываем состояние кнопки
    return current; //возвращаем состояние
  }
return current; //возвращаем состояние
}

void setMode (int mode) //функция для выполнения моргания. void т.к. она ничего не вычисляет
{

  if (mode == 0) //если режим равен 0
  {
    Blink (GREEN1_INTERVAL1, GREEN1); //моргаем на выводе GREEN1 с интервалом GREEN1_INTERVAL1
  }
  else if (mode == 1) //если режим равен 1 
  {
    Blink (GREEN1_INTERVAL2, GREEN1);
  }
  else if (mode == 2) //если режим равен 2
  {
    digitalWrite (GREEN1, LOW); //выключаем питание
  }
}

void Blink (unsigned long INTERVAL, int LED_PIN) //функция воспринимает интервал и пин вывода в качетсве входных параметров
{

  unsigned long Time = millis(); //записываем время работы контроллера
  if (Time - previousTime > INTERVAL) //если прошло достаточно времени, то
  {
    previousTime = Time; //перезаписываем время
    digitalWrite(LED_PIN, !digitalRead(LED_PIN));
  }
}

void loop()
{
//
  currentButton = debounce(lastButton); //подаём функции debounce текущее состояние кнопки, по сути считываем состояние с учётом дребезга
  if (lastButton == LOW && currentButton == HIGH) //если кнопка нажата
  {
    lmode++;    //увеличиваем состояние счётчика режима на 1
  }
  lastButton = currentButton; //запоминаем последнее состояние кнопки
  if (lmode == 3) //если счётчик дошёл до значения 3, которое не предусмотрено в теле функции setMode
  lmode = 0; //то мы его обнуляем
  setMode (lmode); //и передаём значение функции setMode
}

 

Женёк
Offline
Зарегистрирован: 21.12.2015

Огромное спасибо! Всё-таки надо мне подтянуть "азы" :)

P.S. C точки зрения эффективности использования памяти, есть разница между такой записью:

#define GREEN1 3

и такой:

const int GREEN1 = 3;

Или это одно и то же по сути?

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014

Да но это не ошибка а оптимизация кода.

Женёк
Offline
Зарегистрирован: 21.12.2015

Я понимаю, что не ошибка. Даже вот так будет работать:

int GREEN1 = 3;

А в чём оптимизация? Как-то скажется на быстродействии/памяти, или это вопрос стиля?

И ещё вопрос новичка. Есть вот такой код:

if (//условие 1 == true)
{
//действие 1
}
if (//условие 2 == true)
{
действие 2
}
if (условие 3 == true)
{
действие 3
}

Если "условие 1" ложно, будут ли выполняться второй и третий блоки if?

vvadim
Offline
Зарегистрирован: 23.05.2012

будут

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014
Не зависимо от результата 1 условия остальные тоже будут проверяться
Если мы пишем int Gren1 = 3; процесор выделяет память под эту переменную, а c #define 3 - нет, она нам в даном случае не нужна.
Женёк
Offline
Зарегистрирован: 21.12.2015

Опять проблемы :D Добавил в функцию setMode() вот такой блок:

 else if (mode == 3) //если режим равен 3
  {
    digitalWrite (GREEN1, HIGH); //включаем питание
  }

И в строке 67 сделал так:

if (lmode == 4) //если счётчик дошёл до значения 3, которое не предусмотрено в теле функции 

И не работает, либо выключен диод, либо моргает с интервалом GREEN1_INTERVAL1. В чём может быть дело?

Не работает на чётном числе режимов. Если добавить ещё один (я добавил свечение в полнакала через ШИМ), и заменить на lmode==5, то опять работает :)

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014

Я сделал так как Вы описали и все отлично работает

#define GREEN1 3 //контакт 3 для светодиода
#define BUTTON 2 //контакт 2 для кнопки
boolean lastButton = LOW; //переменная для хранения последнего состояния кнопки
boolean currentButton = LOW; //переменная для хранения текущего статуса кнопки
int lmode = 2; //переменная для статуса светодиода
int GREEN1_INTERVAL1 = 100; //100 мс для моргания 10 Гц
int GREEN1_INTERVAL2 = 500; //500 мс для моргания 2 Гц
unsigned long previousTime = 0;


void setup()
{
  pinMode (GREEN1, OUTPUT); //устанавливаем пин3 как выход
  pinMode (BUTTON, INPUT); //устанавливаем пин2 как вход
//Serial.begin(9600); 
}

boolean debounce(boolean last) //функция сглаживания, выдает значения HIGH или LOW
{
  boolean current = digitalRead(BUTTON); //считываем состояние кнопки
  if (last != current) //если не такое, как было
  {
    delay(10); //то ждём 10 мс
    current = digitalRead(BUTTON); //опять считываем состояние кнопки
    return current; //возвращаем состояние
  }
return current; //возвращаем состояние
}

void setMode (int mode) //функция для выполнения моргания. void т.к. она ничего не вычисляет
{

  if (mode == 0) //если режим равен 0
  {
    Blink (GREEN1_INTERVAL1, GREEN1); //моргаем на выводе GREEN1 с интервалом GREEN1_INTERVAL1
  }
  else if (mode == 1) //если режим равен 1 
  {
    Blink (GREEN1_INTERVAL2, GREEN1);
  }
  else if (mode == 2) //если режим равен 2
  {
    digitalWrite (GREEN1, LOW); //выключаем питание
  }
  else if (mode == 3) //если режим равен 3
 {
   digitalWrite (GREEN1, HIGH); //включаем питание
 }
}

void Blink (unsigned long INTERVAL, int LED_PIN) //функция воспринимает интервал и пин вывода в качетсве входных параметров
{

  unsigned long Time = millis(); //записываем время работы контроллера
  if (Time - previousTime > INTERVAL) //если прошло достаточно времени, то
  {
    previousTime = Time; //перезаписываем время
    digitalWrite(LED_PIN, !digitalRead(LED_PIN));
  }
}

void loop()
{
//
  currentButton = debounce(lastButton); //подаём функции debounce текущее состояние кнопки, по сути считываем состояние с учётом дребезга
  if (lastButton == LOW && currentButton == HIGH) //если кнопка нажата
  {
    lmode++;    //увеличиваем состояние счётчика режима на 1
  }
  lastButton = currentButton; //запоминаем последнее состояние кнопки
  if (lmode == 4) //если счётчик дошёл до значения 3, которое не предусмотрено в теле функции setMode
  lmode = 0; //то мы его обнуляем
  setMode (lmode); //и передаём значение функции setMode
}

 

recton55
Offline
Зарегистрирован: 28.01.2020

как ускорить генерацию до килогерц ?

я ставил интервал 0 и генерация слабая мне нужно больше частоту 

как это сделать?

nik182
Offline
Зарегистрирован: 04.05.2015

Сокращать время выполнения цикла. Теоретический предел около мегагерца. У Вас есть куда стремиться.