Программирование режимов светодиода

guliyev34
Offline
Зарегистрирован: 17.03.2015

Здравствуйте, друзья! Реализовал небольшое устройство на Arduino, для собственного развития. Суть состоит в следующем: имеется светодиод, 3 кнопки и LCD дисплей (16х2). На дисплее выводится меню. Всего имеется 2 пункта. В первом пункте происходит включение/выключение светодиода, во втором меню - выбор режимов работы. Кнопками (назовем их L,R,OK) , происходит переключение между пунктами (L,R кнопки), а также изменение текущего состояния светодиода (кнопка ОК). Вот скетч такого устройства:

//подключение библиотеки для работы с LCD
#include <LiquidCrystal.h>

//управляющие кнопки
int button_L = 8; //кнопка переключения влево
int button_OK = 7; //кнопка переключения вправо
int button_R = 9; //кнопка ОК

//управляемый светодиод
int led = 6;

//состояние кнопки
boolean lastButton_L = LOW;
boolean currentButton_L = LOW;
boolean lastButton_R = LOW;
boolean currentButton_R = LOW;
boolean lastButton_OK = LOW;
boolean currentButton_OK = LOW;

//переменная отвечающая за пункт меню
int punkt = 0; //0 - включить/выключить, 1 - меню режима

//переменные отвечающие за параметры светодиода
boolean mode_led = LOW; //режим светодиода
boolean on_off = LOW; //включен или выключен

//инициализируем LCD с указанием контактов
LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);

//====================================================

void setup()
{
//инициализируем пины
pinMode(button_L, INPUT);    
pinMode(button_R, INPUT);  
pinMode(button_OK, INPUT);
pinMode(led,OUTPUT);

//начало работы, с указанием размерности экрана
lcd.begin(16,2);
}

//====================================================

void loop()
{ 
//проверяем нажатие кнопки button_L  
F_button_L();
//проверяем нажатие кнопки button_R 
F_button_R();
//проверяем нажатие кнопки button_OK 
F_button_OK();

//переводим светодиод в настроенное состояние
F_led();
//очищаем экран
lcd.clear();
//выводим на экран текущее состояние
enable_print();
//выводим внизу экрана меню
menu();
//небольшая задержка между кадрами
delay(50);
}

//=================проверяем нажатие кнопки button_L 
void F_button_L()
 {
 if (lastButton_L != digitalRead(button_L))
 {
    delay(5);
    currentButton_L = digitalRead(button_L);
 }
 if (lastButton_L == LOW && currentButton_L == HIGH)
 {
   if (punkt >0)//чтобы не выходить за заданное количество пунктов меню
   {
    punkt--; //если нажата кнопка, переключаем на предыдущее меню 
   }
   else punkt = 1;
 }
 lastButton_L = currentButton_L;
}
//=================проверяем нажатие кнопки button_R 
void F_button_R()
 {
 if (lastButton_R != digitalRead(button_R))
 {
    delay(5);
    currentButton_R = digitalRead(button_R);
 }
 if (lastButton_R == LOW && currentButton_R == HIGH)
 {
   //чтобы не выходить за заданное количество пунктов меню
   if (punkt < 1)
   {
    punkt++; //если нажата кнопка, переключаем на следующее меню 
   }
   else punkt = 0;
 }
 lastButton_R = currentButton_R;
}
//=================проверяем нажатие кнопки button_OK
void F_button_OK()
 {
 if (lastButton_OK != digitalRead(button_OK))
 {
    delay(5);
    currentButton_OK = digitalRead(button_OK);
 }
 if (lastButton_OK == LOW && currentButton_OK == HIGH)
 {
   tools(); //если нажали кнопку ОК, переходим в настройку состояния
 }
 lastButton_OK = currentButton_OK;
}
//==========================изменяем параметры системы
void tools()
{
  if (punkt == 0)
  {
    if (!on_off)
    {
       on_off=HIGH; //переводим состояние светодиода в ВКЛЮЧЕНО
    }
    else 
    {
       on_off=LOW; //переводим состояние светодиода в ВЫКЛЮЧЕНО   
    }
  }
  else
  {
    if (!mode_led)
    {
      mode_led = HIGH; 
    }
    else
    {
      mode_led = LOW;
    }
  }
}
//=================выводим на экран текущее состояние
void enable_print()
{
  if (punkt == 0) //если в первом пункте меню
  {
    if (!on_off) //если светодиод выключен
    {
      lcd.print("LED: OFF!");
    }
    else //если светодиод включен
    {
      lcd.print("LED: ON!"); 
    }
  }
  else //если во втором пункте меню
  {
    if (!mode_led)
    {
      lcd.print("MODE: 1");
    }
    else
    {
      lcd.print("MODE: 2");          
    }
  }
}
//=======================настройка режимов светодиода
void F_led()
{
  if (on_off)
  {
  if (!mode_led)
  {
     digitalWrite(led,HIGH);   
  }
  else
  {
     analogWrite(led,100); 
  }
  }
  else digitalWrite(led,LOW);
}
//==========================выводим внизу экрана меню
void menu()
{
 lcd.setCursor(0,1);
 lcd.print("<--"); 
 lcd.setCursor(7,1);
 lcd.print("OK"); 
 lcd.setCursor(13,1);
 lcd.print("-->"); 
}
//===================================================

Этот код полностью рабочий. Реализовано 2 режима. 1 - свечение светодиода с максимальной яркостью. 2- светодиод горит тусклее. 

Прошу, если будут какие-то недочеты по коду, тыкать в эти места носом, так как я только учусь, и хотелось бы видеть и понимать свои ошибки. 

Теперь перейдем к самой проблеме. Изначально хотелось сделать 3 режима. 1 - горит постоянно. 2- моргает. 3 - сначала загорается плавно, потом плавно погасает. Но когда начал делать это. То получалось следующее: все работало без ошибок на первом режиме. Как только переходил на режим 2, кнопками уже ничего не мог сделать. Т.к выполнялся цикл мигания. И нужно было ждать до конца. А хотелось бы сделать так, чтобы светодиод выполнял свою работу, а я мог в это же время нажимать кнопки, и просматривать меню. Не могли бы Вы помочь разобраться с данной проблемой? 

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

А смысл какой, прилагать рабочий скетч? В нем проблем нет, согласно Вашей же информации.

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

В код не заглядывал, но, судя по словесному описанию, Вам нужно как следуект радобраться в "blink without delay".

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

Так кода и нет, заглядывать некуда. В приложенном коде delay(100500) отсутствует. Короче это не тот код, по которому описана проблема.

 

 

guliyev34
Offline
Зарегистрирован: 17.03.2015

Код был добавлен специально, т.к я знаю что можно было бы описать все иначе и проще. Думал поправите. Нерабочий код вот в этой строке:

//=======================настройка режимов светодиода
void F_led()
{
  if (on_off)
  {
  if (!mode_led) //режим 1
  {
     digitalWrite(led,HIGH);  
  }
  else //режим 2
  {
     digitalWrite(led,HIGH);
     delay(500);
     digitalWrite(led,LOW);
     delay(500);
  }
  }
  else digitalWrite(led,LOW);
}

И вернемся к самой сути проблемы:

Теперь перейдем к самой проблеме. Изначально хотелось сделать 3 режима. 1 - горит постоянно. 2- моргает. 3 - сначала загорается плавно, потом плавно погасает. Но когда начал делать это. То получалось следующее: все работало без ошибок на первом режиме. Как только переходил на режим 2, кнопками уже ничего не мог сделать. Т.к выполнялся цикл мигания. И нужно было ждать до конца. А хотелось бы сделать так, чтобы светодиод выполнял свою работу, а я мог в это же время нажимать кнопки, и просматривать меню. Не могли бы Вы помочь разобраться с данной проблемой?

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

А теперь найдите этот кусок из сообщения #4 в скетче, который приложили в первом сообщении.

Ответ на вопрос уже прозвучал в сообщении #2.

 

guliyev34
Offline
Зарегистрирован: 17.03.2015

kisoft пишет:

А теперь найдите этот кусок из сообщения #4 в скетче, который приложили в первом сообщении.

Я приложил тот скетч для проверки. Чтобы просто посмотрели и сделали замечания по написанию. А на счет режимов просто хотелось узнать. Можно ли сделать так, чтобы светодиод выполнял свою работу (моргал, потухал и снова начинал светиться), а я в это время мог спокойно перемещаться по меню. 

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

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

К первому - нет замечаний.

Так ответ по существу проблемы уже прозвучал: "Ответ на вопрос уже прозвучал в сообщении #2."

Или еще проще: ДА

 

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

 guliyev34 Посмотрите этот код, старался по максимому сохранить Ваш чтоб Вам было легче розобраться. Здесь можно ставить меню не 3 а больше немного подправив код. Думаю разберетесь


//подключение библиотеки для работы с LCD
#include <LiquidCrystal.h>

//управляющие кнопки
int button_L = 8; //кнопка переключения влево
int button_OK = 7; //кнопка переключения вправо
int button_R = 9; //кнопка ОК

//управляемый светодиод
int led = 6;

//состояние кнопки
boolean lastButton_L = LOW;
boolean currentButton_L = LOW;
boolean lastButton_R = LOW;
boolean currentButton_R = LOW;
boolean lastButton_OK = LOW;
boolean currentButton_OK = LOW;

//переменная отвечающая за пункт меню
int f_punkt = 0;//Временная для ОК
int punkt = 0; //0 - включить/выключить, 1 - меню режима

int t1 = 500; //Время для мигания
unsigned long x; //Переменная для прошедшего периода "led"
int brightness = 0;     // яркость светодиода
int fadeAmount = 3;     // шаг изменения яркости

//инициализируем LCD с указанием контактов
LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);

//====================================================

void setup()
{
  //инициализируем пины
   pinMode(button_L, INPUT); //  пин, как вход + подтягивающий резистор
   pinMode(button_R, INPUT);
   pinMode(button_OK, INPUT);
   pinMode(led, OUTPUT);

  //начало работы, с указанием размерности экрана
  lcd.begin(16, 2);
   Serial.begin(9600);
}

//====================================================



//=================проверяем нажатие кнопки button_L
void F_button_L()
{
  if (lastButton_L != digitalRead(button_L))
  {
    delay(5);
    currentButton_L = digitalRead(button_L);
  }
  if (lastButton_L == LOW && currentButton_L == HIGH)
  {
  f_punkt--; //если нажата кнопка, переключаем на предыдущее меню
    if (f_punkt <= 0)f_punkt = 1; //чтобы не выходить за заданное количество пунктов меню
  }
  lastButton_L = currentButton_L;
}
//=================проверяем нажатие кнопки button_R
void F_button_R()
{
  if (lastButton_R != digitalRead(button_R))
  {
    delay(5);
    currentButton_R = digitalRead(button_R);
  }
  if (lastButton_R == LOW && currentButton_R == HIGH)
  {
     f_punkt++; //если нажата кнопка, переключаем на следующее меню
     if (f_punkt >= 4)f_punkt = 1;//чтобы не выходить за заданное количество пунктов меню
    
  }
  lastButton_R = currentButton_R;
}
//=================проверяем нажатие кнопки button_OK
void F_button_OK()
{
  if (lastButton_OK != digitalRead(button_OK))
  {
    delay(5);
    currentButton_OK = digitalRead(button_OK);
  }
  if (lastButton_OK == LOW && currentButton_OK == HIGH)
  {
    punkt = f_punkt; //если нажали кнопку ОК, переходим в настройку состояния
      Serial.println(punkt); //Выводим на монитор
  }
  lastButton_OK = currentButton_OK;

}

//=================экран текущее состояние
void enable_print()
{
  switch (punkt)
  {
    case 1:
      lcd.print("MODE: 1");
      break;
    case 2:
      lcd.print("MODE: 2");
      break;
    case 3:
      lcd.print("MODE: 3");
      break;
  }

}
//=======================настройка режимов светодиода
void F_led()
{
  switch (punkt)
  {
    case 1:
      digitalWrite(led, HIGH);
      break;

    case 2:
      if (x != (millis() / t1))
      {
        x = millis() / t1;
        digitalWrite(led, !digitalRead(led));
      }
      break;

    case 3:
      if (x != (millis() / 20))
      {
        analogWrite(led, brightness);    // устанавливаем значение на 6 ножке
        brightness = brightness + fadeAmount;   // прибавляем шаг яркости
        // если достигли мин. или макс. значения, то идем в обратную сторону
        if (brightness == 0 || brightness == 255) {
          fadeAmount = -fadeAmount ;
        }
        x = millis() / 20;
      }
      break;
  }
}
//==========================выводим внизу экрана меню
void menu()
{
  lcd.setCursor(0, 1);
  lcd.print("<--");
  lcd.setCursor(7, 1);
  lcd.print("OK");
  lcd.setCursor(13, 1);
  lcd.print("-->");
}

void loop()
{
  //проверяем нажатие кнопки button_L
  F_button_L();
  //проверяем нажатие кнопки button_R
  F_button_R();
  //проверяем нажатие кнопки button_OK
  F_button_OK();

  //переводим светодиод в настроенное состояние
  F_led();
  //очищаем экран
  lcd.clear();
  //выводим на экран текущее состояние
  enable_print();
  //выводим внизу экрана меню
  menu();
  //небольшая задержка между кадрами
  delay(50);
}

 

guliyev34
Offline
Зарегистрирован: 17.03.2015

vosara Спасибо большое за код. Очень интресно, а главное все заработало. Правда есть недработки, например, при первом запуске устройства на экране выводится только нижнее меню. А также для переключения режима, недостаточно просто нажать кнопку ОК, нужно сначала нажать Левую кнопку, а затем уже Ок. Но это все не важно, главное сама идея. Вы не могли бы объяснить работу режима, на примере вот этих строк:

    case 2:
      if (x != (millis() / t1))
      {
        x = millis() / t1;
        digitalWrite(led, !digitalRead(led));
      }
      break;

Я понимаю то, что у нас будут выполняться эти строки, когда punkt будет равен 2. Также понятно, что break завершает switch функцию, а благодаря этой строке: digitalWrite(led, !digitalRead(led)) , состояние светодиода, при каждом проходе, будет меняться, и будет создаваться эффект мигания. Но вот операции с millis не совсем понятны. 

Например, при первом проходе, x мы объявили, tl у нас равно 500. Значит, условие будет выполнено и x у нас не будет равно millis/tl. Мы присваем x значение millis/tl. И изменяем состояние светодиода (было LOW - стало HIGH). Потом прирываем switch? И дальше делаем все сначала? Т.е переходим снова в функцию loop и проверяем были ли нажаты кнопки? Я просто немного не понимаю как это все работает :(( 

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014
По первому пункту, у нас меню завьязано на переменной "punkt" которой присваюется значение "f_punkt" по кнопке "ок", а в самом начале мы им присвоили значение 0, поэтому вначале "ок" ничего не меняет.
Если хотите то присвойте f_punkt=1 и по нажатии "ок" войдете в меню 1.
Строчка if (x != (millis() / t1)) равносильна - if(millis() - x >= t1). А так Вы все правильно поняли, лооп будет крутиться пока не выполниться условие  if (x != (millis() / t1)). Я так понял что этод код Вы создали в учебных целях.
guliyev34
Offline
Зарегистрирован: 17.03.2015

vosara пишет:

Я так понял что этод код Вы создали в учебных целях.

Да, именно так. Я пока только учусь. Вот решил сделать такое устройство, свого рода контроль управления. 

vosara пишет:

лооп будет крутиться пока не выполниться условие  if (x != (millis() / t1))

Получается что через каждые 500 мсек(tl) происходит переключение на операцию мигания светодиода? А все остальное время мы можем тыкать кнопки?

Спасибо большое за помощь, многое стало на свои места)) Побольше бы таких людей