Работа с кнопками. В помощь новичку.

nestandart
nestandart аватар
Offline
Зарегистрирован: 15.06.2011

 

Ардуино и кнопка.

Кнопка – простейшее электромеханическое устройство.
Кнопки бывают двух видов.

1.Кнопки (переключатели) с фиксированным положением.
2.Так называемые тактовые кнопки (которые возвращаются в исходное положение).

 

 

С первыми все ясно, а вот как работать со вторыми ?

В этой статье я расскажу, как правильно подключить кнопку к МК и как работать с ней программно. Так же расскажу, как подключить несколько кнопок к одному пину МК.

Обычно, самый первый раз, кнопку пытаются подключить вот так.
Это НЕ ПРАВИЛЬНОЕ подключение.

 

 

Дело в том, что пин МК (в режиме входа) должен иметь заранее известное состояние (1или 0).
В «подвешенном» состоянии будет собирать внешние наводки (статические, электрические и электромагнитные излучения).
Чтобы привести пин в заранее известное состояние и используют подтягивающие резисторы.
Они бывают двух видов, верхние и нижние подтяжки.
Верхние (pull-up) подключаются к плюсу питания и нижние (pull-down) к минусу.
В ардуино есть встроенные подтягивающие резисторы (pull-up) которые можно включить программно, но я не советую их использовать.

 

ПРАВИЛЬНОЕ подключение кнопки.

 

 

В данном случае, когда кнопка отключена, пин будет подключен к земле через резистор, сопротивление которого заведомо меньше внутреннего сопротивления пина.
Поэтому наводка, попавшая на пин, стечет в землю. Если же подключен полезный сигнал (+5в) то он будет стекать в пин (незначительная часть сигнала стечет в землю через подтяжку).

В итоге, при нажатой кнопке, у нас будет стабильный сигнал (+5в), а при отпущенной кнопке будет стабильный ноль.

 

Рассмотрим несколько простых программных примеров.

 

void setup() 
 { 

 pinMode(13, OUTPUT); 

 } 

 void loop() 

 { 

 digitalWrite(13,analogRead(14)); //состояние входа равно состоянию выхода 

 } 
 

Это самый простой пример. Немного усложним его

 

void setup() 
 { 

 pinMode(13, OUTPUT); 

 } 

 void loop() 

 { 
 if(digitalRead(14)==HIGH)//если кнопка нажата ... 
 { 
 digitalWrite(13,HIGH);//включаем светодиод 
 } 
 else//если не нажата... 
 { 
 digitalWrite(13,LOW);//выключаем 
 } 

 } 

 

 

Этот пример можно инвертировать. Когда кнопка не жата светодиод горит, когда нажата – нет.

Идем дальше.

void setup()     
 { 
          
      pinMode(13, OUTPUT);          
         
           
 } 

 void loop() 

 { 
      if(digitalRead(14)==HIGH)//если кнопка нажата ... 
      { 
      digitalWrite(13,!digitalRead(13));//инвертируем состояние пина 

      delay(500);//небольшая защита от "дребезга" контактов кнопки 
      } 
          
          
 } 

 

 

Если удерживать кнопку, то получим мерцание светодиода с частотой заданной функией delay.

А если нам нужно включить что то по удержанию кнопки?

Для этого введем переменную val.

 

 

int val=0; 

 void setup()     
 { 
          
      pinMode(13, OUTPUT);          
         
           
 } 

 void loop() 

 { 
      if(digitalRead(14)==HIGH)//если кнопка нажата ... 
      { 
        val++;// прибавляем к переменной 1 при каждой смене цикла. 
          
      delay(500);//небольшая защита от "дребезга" контактов кнопки 
      } 
      else 
      { 
        val=0; 
      } 
          
      if(val>=5) 
      { 
        digitalWrite(13,!digitalRead(13));//инвертируем состояние пина 
        val=0; 
      } 
          
          
 } 
 

 

Здесь я использовал простейший «самодельный» таймер.

Рассмотрим пример с более сложным таймером.

 

long previousMillis = 0; 
 int val=0; 

 void setup()    
 { 
        
     pinMode(13, OUTPUT);         
       
         
 } 

 void loop() 

 { 
     if(digitalRead(14)==HIGH)//если кнопка нажата ... 
     { 
         
      if (millis() -previousMillis >500)    
     { 
        previousMillis = millis();     
        val++; 
     } 
     } 
     else 
     { 
       val=0; 
     } 
        
     if(val>=5) 
     { 
       digitalWrite(13,!digitalRead(13));//инвертируем состояние пина 
       val=0; 
     } 
        
        
 } 
 

 

 

 

Основной плюс этого таймера это то, что он не использует паразитную функцию delay и, соответственно, не тормозит программу.
Очень не советую использовать функцию pulseIn для данных целей (да и вообще не советую).
Потому что эта функция использует все программные таймеры ардуино.
С функцией pulseIn НЕ будут работать
Tone()
Millis()
analogWrite()
Так же не будут работать сервоприводы.

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

 

 int flag=0; 

 void setup()    
 { 
        
     pinMode(13, OUTPUT);         
       
         
 } 

 void loop() 

 { 
         
      if(digitalRead(14)==HIGH&&flag==0)//если кнопка нажата    
      // и перемення flag равна 0 , то ... 
      { 
            
        digitalWrite(13,!digitalRead(13)); 
        flag=1; 
         //это нужно для того что бы с каждым нажатием кнопки 
         //происходило только одно действие 
         // плюс защита от "дребезга"  100% 
         
      } 
         
       if(digitalRead(14)==LOW&&flag==1)//если кнопка НЕ нажата 
      //и переменная flag равна - 1 ,то ... 
      { 
            
         flag=0;//обнуляем переменную flag 
      } 
 } 

 

 

Алгоритм такой. Нажали кнопку – загорелся светодиод, удерживаем кнопку – ничего не происходит (светодиод горит). Отпустили кнопку – светодиод горит.
Для того чтобы погасить светодиод нужно повторно нажать кнопку.
Т.е. нажали – горит, отпустили, нажали – не горит.

Можно инвертировать действие вот так

 

 

int flag=0; 

 void setup()   
 { 
      
    pinMode(13, OUTPUT);        
     
       
 } 

 void loop() 

 { 
       
     if(digitalRead(14)==HIGH&&flag==0)//если кнопка нажата   
     // и перемення flag равна 0 , то ... 
     { 
          
        
       flag=1; 
        //это нужно для того что бы с каждым нажатием кнопки 
        //происходило только одно действие 
        // плюс защита от "дребезга"  100% 
       
     } 
       
      if(digitalRead(14)==LOW&&flag==1)//если кнопка НЕ нажата 
     //и переменная flag равна - 1 ,то ... 
     { 
         digitalWrite(13,!digitalRead(13)); 
        flag=0;//обнуляем переменную flag 
     } 
 } 

 

 

Нажали – ничего, отпустили – горит. Повторно нажали, отпустили – не горит.

Теперь сделаем небольшое меню.
Меню будет содержать четыре режима (можно сколько угодно, но для примера хватит и четырех).
Меню будет управлять двумя светодиодами.
Введем еще одну переменную – regim.

 

int regim=1; 
 int flag=0; 

 void setup()   
 { 
    pinMode(10,OUTPUT);    
 pinMode(9,OUTPUT);    
       
 } 

 void loop() 

 { 
       
     if(digitalRead(14)==HIGH&&flag==0)//если кнопка нажата   
     // и перемення flag равна 0 , то ... 
     { 
       regim++;   
       flag=1; 
         
        //это нужно для того что бы с каждым нажатием кнопки 
        //происходило только одно действие 
        // плюс защита от "дребезга"  100% 
          
        if(regim>4)//ограничим количество режимов 
        { 
          regim=1;//так как мы используем только одну кнопку, 
                    // то переключать режимы будем циклично 
        } 
       
     } 
       
      if(digitalRead(14)==LOW&&flag==1)//если кнопка НЕ нажата 
     //и переменная flag равна - 1 ,то ... 
     { 
          
        flag=0;//обнуляем переменную "knopka" 
     } 
      
       
       
    if(regim==1)//первый режим 
    { 
      digitalWrite(9,LOW);//выключаем все светодиоды 
      digitalWrite(10,LOW); 
        
        
      //здесь может быть любое ваше действие 
    } 
    if(regim==2)//второй режим 
    { 
      digitalWrite(10,HIGH);//включае красный светодиод 
      digitalWrite(9,LOW); 
        
      //здесь может быть любое ваше действие 
    } 
      
    if(regim==3)//третий режим 
    { 
        
      digitalWrite(9,HIGH);//включае зеленый светодиод 
      digitalWrite(10,LOW); 
        
        
      //здесь может быть любое ваше действие 
    } 
      
    if(regim==4)//четвертый режим 
    { 
        
      digitalWrite(9,HIGH);//включаем светодиоды одновременно 
      digitalWrite(10,HIGH); 
      //здесь может быть любое ваше действие 
    } 
      
 } 

 

 

 

nestandart
nestandart аватар
Offline
Зарегистрирован: 15.06.2011

Внутреннй подтягивающий резистор.

В микроконтроллерах ATmega168 и ATmega328 есть внутренние подтяжки. Они имеют номинал 20Ком и включаются программно. Нужно иметь в виду что внутренняя подтяжка "Прижимает" пин только к +5в.

В связи с этим нужно инвертировать логику.

Ранее мы рассматривали примеры в которых одна нога кнопки подключена к +5,вторая к пину а пин к GND (через внешнюю подтяжку) . С внутренней подтяжкой все наоборот.

Одна нога кнопки подключается к GND, другая к пину (никаких внешних резисторов не нужно).

В этом случае 1 на цифровом входе означает отсутствие сигнала а 0 - присутствие.

Вот простой пример включения внутренней подтяжки.

 

void setup() 
{

pinMode(13,OUTPUT);//конфигурируем пин как выход ( к нему подключен светодиод)
digitalWrite(14,HIGH);//включаем внутренний pull-up резистор
}

void loop() 
{
  
  
    digitalWrite(13,!digitalRead(14));//устанавливаем значение выхода 13 противоположное 
   //входу 14 . Т.е. когда на входе LOW (есть сигнал) на выходу устанавливаем HIGH
 
  
 
}

 

 

 

Делитель напряжения и ЦАП.

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

Вот так.

 

 

Данный делитель рассчитывается по формуле

 

 

 

Пример расчета

 

Примем Uвх = 5в , R1 = 1К, R2 = 1К.

5*1/(1+1)=2.5в

Резисторы делителя называют плечами. Верхнее плечо – Uвх, нижнее - GND.
Т.е. R1 – верхнее плечо, R2 – нижнее плечо.
Если номиналы обоих резисторов равны напряжение будет поделено пополам.

Важно знать, что общее сопротивление делителя должно быть значительно меньше сопротивления нагрузки подключенной к нему (примерно в 100 раз).
НО общее сопротивление делителя не должно быть и слишком низким. В этом случае мы получим нагрев делителя и расход тока в пустую.
Не опускайте общее сопротивление ниже 4.7К.
Вобщем, идеальный диапазон сопротивлений от 4.7К до 50К

Теперь рассмотрим ЦАП на основе делителя напряжения.

ЦАП - Цифро-аналоговый преобразователь.
Устройство преобразует цифровой сигнал в аналоговый.

Подключение двух кнопок к одному пину.

На этой схеме изображен простой двух канальный резистивный ЦАП.

 

 

 

Рассмотрим некоторые важные моменты.

Резистор R3 является подтягивающим и его номинал не стоит опускать ниже 4.7К.
В то же время R3 является нижним плечом делителя напряжения.

Когда кнопки не нажаты на пине АЦП – лог 0.

Нажатая кнопка К1 образует делитель напряжения с номиналами плеч R1=4.7K, R2=10K.

Считаем по формуле.
5*10/(4.7+10) = 3.4в

Когда нажата кнопка К2 номиналы делителя будут R1=3 , R2=10K.
5*10/(3+10) = 3.8в.
Но что произойдет, если обе кнопки будут нажаты одновременно?

В этом случае верхнее плечо делителя будет состоять из двух резисторов R1 и R2 включенных параллельно.

Общий номинал параллельно включенных резисторов считаем по формуле

 

 

Rобщ = (4.7*3)/(4.7+3) = 1.83K

Считаем выходное напряжение делителя

5*10/(1.83+10) = 4.22в.

Напишем простую программу.

 

int analog=0; 
 void setup()    
 {                   
     pinMode(9, OUTPUT);     
     pinMode(10, OUTPUT);      
       
 } 

 void loop()    
 { 
        
     analog=analogRead(14);//считываем сигнал с пина АЦП 
        
        
     if(analog>690&&analog<700)//здесь я сравниваю    
     //значение входящего сигнала не с конкретной цифрой 
     //а с определенным диапазоном от 690 до 700    
     //это нужно для того чтобы исключить влияние погрешностей резисторов 
     { 
       digitalWrite(9,HIGH); 
       digitalWrite(10,LOW); 
     } 
        
      if(analog>785&&analog<795) 
     { 
       digitalWrite(9,LOW); 
       digitalWrite(10,HIGH); 
     } 
        
     if(analog>860&&analog<870) 
     { 
       digitalWrite(9,HIGH); 
       digitalWrite(10,HIGH); 
     } 
        
     if(analog<100) 
     { 
       digitalWrite(9,LOW); 
       digitalWrite(10,LOW); 
     } 
 } 
 

 

Количество каналов ЦАПа может быть сколь угодно большим (и соответственно количество кнопок).
Нужно точно рассчитывать номиналы резисторов. И уделять особенное внимание соотношениям номиналов между собой.

Ну, вот и все (или почти все) о кнопках.

Данная статья была ранее опубликована мной на  http://forumdvrobot.ru/forum/3-21-1

P.S. Просьба к админам, прикрепите статью куда нибудь , что бы вниз не ушла.

 

maksim
Offline
Зарегистрирован: 12.02.2012

nestandart пишет:
В ардуино есть встроенные подтягивающие резисторы (pull-up) которые можно включить программно, но я не советую их использовать.
А я наоборот советую и рекомендую их использовать, потому как они именно для этого и предназначены.

nestandart
nestandart аватар
Offline
Зарегистрирован: 15.06.2011

Внутренняя подтяжка тянет только вверх. Внешней можно прижать и к земле. 

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

 

Данная статья и примеры программ не являются "Истиной в последней инстанции". Это мой личный опыт и мой личный путь "Проб и ошибок".

 

maksim
Offline
Зарегистрирован: 12.02.2012

И что что она "тянет" только "вверх" - это никак не отражается на качестве работы кнопки. То что нужно потрогать - это да, для обучения/понимания тоже да, но не советовать ими пользоваться это на мой взгляд не верно, не нужно вводить в заблуждение "новичков", что внутренняя подтяжка - это плохо. Это очень удобная и нужная вещь, просто описание работы кнопок с внутренней подтяжкой выходит за рамки этой статьи.

UPD: И да, кстати, не замечал раньше этого комментария: // плюс защита от "дребезга"  100%   - уберите, не дурите людям голову, нет там никакой защиты от дребезга.

maksim
Offline
Зарегистрирован: 12.02.2012

Одно из решений "аналоговой клавиатуры", которое можно подредактировать и под вашу схему:

#define NUM_KEYS 5
int  adc_key_val[NUM_KEYS] = {30, 150, 360, 535, 760};

void setup()
{
  Serial.begin(9600);
}

void loop() 
{
  int key = get_key(A0);
  if(key) Serial.println(key, DEC);
}

int get_key(int key_pin)
{
  int input = analogRead(key_pin);
  int k;
  for(k = 0; k < NUM_KEYS; k++) 
    if(input < adc_key_val[k]) 
      return k + 1;     
  return 0;
}

данный код написан под эту схему

как видите количество кнопок задается параметром NUM_KEYS,
а "диапазоны" акуратненько "лежат" в массиве adc_key_val[].

nestandart
nestandart аватар
Offline
Зарегистрирован: 15.06.2011

maksim, в приведенной вами схеме не совсем понятно что будет происходить при одновременно нажатых кнопках.

 

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

Убирать скобки очень плохо, формула 5*1/1+1=2.5 убивает, а
5*1/(1+1)=2.5 понимается совсем по другому.

nestandart
nestandart аватар
Offline
Зарегистрирован: 15.06.2011

 

>>Убирать скобки очень плохо, формула 5*1/1+1=2.5 убивает, а
5*1/(1+1)=2.5 понимается совсем по другому.<<

Спасибо что указали ошибку. Исправил.

 

 

mr.il
Offline
Зарегистрирован: 05.01.2013

Народ, привет!

С точки зрения новичка прошу рассмотреть пример подключения кнопки с внутренней подтяжкой.

А так же указать как включать внутреннюю подтяжку.

JollyBiber
JollyBiber аватар
Offline
Зарегистрирован: 08.05.2012
if(analog>690&&analog<700)

а про это где можно подробнее почитать? Если я правильно понимаю, то это 3,4в на первой кнопке? Как вообще этот диапазон вычисляется или есть какие-то табличные значения?

maksim
Offline
Зарегистрирован: 12.02.2012

nestandart пишет:
maksim, в приведенной вами схеме не совсем понятно что будет происходить при одновременно нажатых кнопках.
Просто будет прочитано состояние более нижней кнопки. То есть если нажать S4, то S3 и S2 будут игнорироваться. Схема, кстати, взята вот с такого шилда.

nestandart
nestandart аватар
Offline
Зарегистрирован: 15.06.2011

>>То есть если нажать S4, то S3 и S2 будут игнорироваться. Схема, кстати, взята с коммерческого шилда.<<

Примерно так я и думал. Это не есть хорошо. Достаточно немного изменить включение резисторов и кнопки можно будет отслеживать и две и три и все сразу.

nestandart
nestandart аватар
Offline
Зарегистрирован: 15.06.2011

>>а про это где можно подробнее почитать? Если я правильно понимаю, то это 3,4в на первой кнопке? Как вообще этот диапазон вычисляется или есть какие-то табличные значения?<<

Да это 3.4в . Если вы имеете в виду диапазон АЦП, то это от 0 до 1023 . Что соответствует напряжению от 0 до 5в. Например значение 512 это 2.5в.

А вот вам конкретый множитель - 0.0048828125. Если умножить значение пина АЦП на этоу цифру то получите точное напряжение в вольтах.

 

leshak
Offline
Зарегистрирован: 29.09.2011

mr.il пишет:

Народ, привет!

С точки зрения новичка прошу рассмотреть пример подключения кнопки с внутренней подтяжкой.

А так же указать как включать внутреннюю подтяжку.

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

Ладно. Считайте это не "посылом в документацию", а рассказом "где это искать, если нужно".

Включение - простейшие. Такое же как вообще без потяжки, только не к питанию, а к земле

Включаем подтяжку, банальным digitalWrite(D2,HIGH) - на порте включенном на ВХОД  (надеюсь вы уже прочитали про это в документации).

Работат с подтянутой вверх кнопкой, отличается только одним. Теперь не нажатая кнопка это HIGH, а нажатая LOW. То есть значения "инвертировались".

Вот как выглядит в коде зажигание диода по такой кнопке



void setup(){
  pinMode(13,OUTPUT);// включем порт светика на выход

  // настраиваем порт кнопки  
  pinMode(2,INPUT);// это не обязательно, по умолчанию все порты и так включены на вход. Просто "что-бы явно в коде было видно".
  digitalWrite(2,HIGH); // а вот и подтяжку вверх включили

}

void loop(){
   // как видите кнопка и светик у нас инвертированы по отношению друг к другу
   if(digitalRead(2)==LOW)) digitalWrite(13,HIGH);
                            else digitalWrite(13,LOW);
}

 

leshak
Offline
Зарегистрирован: 29.09.2011

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

Вне зависимости от того внешняя подтяжка или внутреняя, к питанию или земле - между кнопкой и пином дуины должен стоять резистор малого номинала (100 ом).

 

Для чего он нужен? При нормальной работе - ни для чего. Но что произойдет если мы случайно включим порт на ВЫХОД, дадим в него HIGH и нажмем кнопку? У нас на пине образуется 5V, через кнопку они замкнутся на землю и мы полчим короткое замыкание - большой ток через пин. Этим мы имеем шансы спалить пин или даже весь контроллер.

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

Если же там стоит резистор, то, по закону Ома, он пропустит через себя (а значит и через пин) ток, не более чем 5v/100ом=0.05A=50mA. Что тоже чуток многовато для пина,  но "не на долго" - уже не будет "смертельным". 

Но еще раз. Это просто "предупреждение". Это знать нужно, но обычно считают (и я тоже :), что "уж я-то не ошибусь" поэтому "незачем усложнять схему лишним резистором" ;)

nestandart
nestandart аватар
Offline
Зарегистрирован: 15.06.2011

>>Вне зависимости от того внешняя подтяжка или внутреняя, к питанию или земле - между кнопкой и пином дуины должен стоять резистор малого номинала (100 ом).<<

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

leshak
Offline
Зарегистрирован: 29.09.2011

nestandart пишет:

>>Вне зависимости от того внешняя подтяжка или внутреняя, к питанию или земле - между кнопкой и пином дуины должен стоять резистор малого номинала (100 ом).<<

С внешней подтяжкой к земле такого не случиться.

Это почему? Если "подтяжка к земле", значит "кнопка к 5v". Включаем порт на выход, даем в него LOW и зажимаем кнопку (даже "давать" - не обязательно, он там уже будет по дефолту. достаточно включить на выход. так что тут "еще нужней"). Что произойдет если в подтяжке достаточно большой номинал стоит?  К пину подведен 5v, а сам пин, внутри, подключился к земле. Рискнете на свое дуине проверить?  ;)

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

nestandart пишет:

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

Если мы говорим про цифровые пины - не стоит "учитывать". Там довольно большой зазор "что считать логической единицей". К примеру если у нас подтягивающий 20кОм (внутренний такой номинал имеет), то защитный на 100 Ом даст нам падение всего в 0.02V, то есть в итоге на пин прийдется 4.98V  Учитывая что логической единицей считается "все что выше 3v" (не помню точно, но что-то около этой цифры), то подобное падение точно можно не учитывать. 

Вспоминать про него прийдется только если мы таким же макаром, начнем подключатся к аналоговым портам и работать с помощью analogRead, там уже это будет "небольшим искажением".

leshak
Offline
Зарегистрирован: 29.09.2011

Если кому-нибудь захочется разобратся с кнопками/портами "досконально", могу порекомендовать статью  AVR. Учебный курс. Устройство и работа портов ввода-вывода . Там немного, конечно, сложновато для новичка. Статья не "ардуинистая", а просто AVR-микроконтроллер описан (но, ардуина построена именно на нем), но понять "как порт устроен" и "зачем нужен подтягивающий, как он работает" - можно.

Хотя, при желании, все что там описано страшными словами "PIN, PORT, DDR это регистры конфигурации порта." можно использовать и при программировани ардуины. Вместо digitalRead/digitalWrite/pinMode . Но это уже "продвинутый уровень".  Почитать про это можно тут: Прямое управления выходами через регистры микроконтроллера Atmega

Вообщем "дополнительная литература" :)

triada13
Offline
Зарегистрирован: 04.01.2013

nestandart пишет:

long previousMillis = 0; 

 int val=0; 

 void setup()    
 { 
        
     pinMode(13, OUTPUT);         
       
         
 } 

 void loop() 

 { 
     if(digitalRead(14)==HIGH)//если кнопка нажата ... 
     { 
         
      if (millis() -previousMillis >500)    
     { 
        previousMillis = millis();     
        val++; 
     } 
     } 
     else 
     { 
       val=0; 
     } 
        
     if(val>=5) 
     { 
       digitalWrite(13,!digitalRead(13));//инвертируем состояние пина 
       val=0; 
     } 
        
        
 } 
 

Основной плюс этого таймера это то, что он не использует паразитную функцию delay и, соответственно, не тормозит программу.

Прошу прощения, но не содержится ли в этом коде ошибка? Я попробовал этот код в симуляторе но никаких действий не происходит, цикл крутится но на пине 13 "светодиод" не загорается, переменная val имеет значение 0, previuosMillis так же значение 0, внезависимости от нажатия кнопки. Да забыл уточнить цифровой вход кнопки я установил не 14 а 9.

long previousMillis = 0;
int val = 0;

void setup()
{
  pinMode(13, OUTPUT);
  pinMode(9, INPUT);
}

void loop()
{
  if(digitalRead(9) == HIGH)
  {
    if(millis() -previousMillis >500)
    {
      previousMillis = millis();
      val++;
    }
    else
    {
      val=0;
    }
    if(val >=5)
    {
      digitalWrite(13, !digitalRead(13));
      val=0;
    }
  }
}


С уважением.

Александр.

leshak
Offline
Зарегистрирован: 29.09.2011

triada13 пишет:

 

Прошу прощения, но не содержится ли в этом коде ошибка? Я попробовал этот код в симуляторе но никаких действий не происходит, цикл крутится но на пине 13 "светодиод" не загорается, переменная val имеет значение 0, previuosMillis так же значение 0, внезависимости от нажатия кнопки. Да забыл уточнить цифровой вход кнопки я установил не 14 а 9.

Очень похоже что вы руками перенабирали этот пример и допустили ошибку (иначе как понять что у вас "millis() -previousMillis >500" превратилось в  "millis() *previousMillis >500" ).

Прочитайте, внимательней ветку Вставка программного кода в тему/комментарий Там описанно и как правильно "забирать к себе код" с форума.

triada13
Offline
Зарегистрирован: 04.01.2013

Leshak да я действительно забивал код от руки с экрана телевизора, и в этом месте символ не оч четабилен, вот я и пробовал подставлять другой знак но всеравно у меня цикл крутится в "холостую".

В данный момент он имеет такой вид:

long previousMillis = 0;
int val = 0;

void setup()
{
  pinMode(13, OUTPUT);
  pinMode(9, INPUT);
}

void loop()
{
  if(digitalRead(9) == HIGH)
  {
    if(millis() -previousMillis >500)
    {
      previousMillis = millis();
      val++;
    }
    else
    {
      val=0;
    }
    if(val >=5)
    {
      digitalWrite(13, !digitalRead(13));
      val=0;
    }
  }
}

P.S.

nestandart очень приятно встретить земляка, я с Ленинска-Кузнецкого. Сори за флуд.

leshak
Offline
Зарегистрирован: 29.09.2011

 

Я бы, еще, посоветовал поменить "long previousMillis = 0" на "unsigned long previousMillis = 0". Не существенно (проблема проявится только при непрерывной работе дуины более 24-рех дней), но "так правильней будет".

triada13 пишет:

Leshak да я действительно забивал код от руки с экрана телевизора, и в этом месте символ не оч четабилен, вот я и пробовал подставлять другой знак но всеравно у меня цикл крутится в "холостую".

А в чем это проявляется? Вы учитываете что для того что-бы он "что-то сделал" (переключил светик) нужно пять-раз нажать кнопку, с интервалом нажатий не быстрее чем пол-секунды? Хотя.... возможно я не понял что тут netstanart хотел показать сделать. Пусть он лучше сам ответит. Лично бы я попробовал бы выкинуть ветку  else   {      val=0;    }  (кстати, ее вы тоже "набрали не туда", так что "осваивать по телевизору" - было явно плохой идеей).

А ишо, возможно, стоило вынести в отдельную ветку разбирательство именно с вашим примером. Оставить ее более чистой в качестве "учебного материала". Без разбирательств "ошибок набора".

Так же, если вы в симуляторе это гоняете. У вас может быть неправильно выставленна тактовая частота/фьюзы для камня. И все millis() будут врать (камень работает очень медленно, и "пол секунды" превратся в минуты).

nestandart
nestandart аватар
Offline
Зарегистрирован: 15.06.2011

>>nestandart очень приятно встретить земляка, я с Ленинска-Кузнецкого. Сори за флуд.<<

Никогда бы не подумал что в этом богом забытом краю есть еще люди увлекающиеся электроникой.

triada13, вот зачем вы набиваете программу вручную ? Если навести курсор на код , то в правом верхнем углу появляется набор значков, нажимаете значек "КОД" и копируете.

 

Вот сейчас , не поленился, спаял схему , залил ВАШ последний код - действительно не работает. НЕ  МОЖЕТ БЫТЬ! Ведь во время написания статьи я несколько раз тестил все программы на реальном железе. Потом залил свою первоначальную программу.

Работает! 

А теперь вопрос к вам triada13 ,найдете свою ошибку с трех раз ?

Странно что компилятор вообще "Съел" вашу программу.

nestandart
nestandart аватар
Offline
Зарегистрирован: 15.06.2011

>>Вы учитываете что для того что-бы он "что-то сделал" (переключил светик) нужно пять-раз нажать кнопку, с интервалом нажатий не быстрее чем пол-секунды? Хотя.... возможно я не понял что тут netstanart хотел показать сделать.<<

Это задержка действия. Нажимаем на кнопку и держим. Действие происходит после пяти секунд удержания кнопки. 

nestandart
nestandart аватар
Offline
Зарегистрирован: 15.06.2011

>>Нажимаем кнопку....., 2-10 светодиодов включаются по порядку с задержкой например 1 секунда, ну и выключаются в обратном порядке .<<

На днях поработаю с вашей просьбой.

leshak
Offline
Зарегистрирован: 29.09.2011

nestandart пишет:

Вот сейчас , не поленился, спаял схему , залил ВАШ последний код - действительно не работает. НЕ  МОЖЕТ БЫТЬ! Ведь во время написания статьи я несколько раз тестил все программы на реальном железе. Потом залил свою первоначальную программу.

Работает! 

Чудеса да и только. Я не понимаю КАК оно может работать? Если оно постоянно val в ноль сбрасывает, сразу при отпускании кнопки? val у нас поднятся больше единицы - не может в принципе. А значит и достичь 5-ть что-бы переключить светик.

Ну может "чего-то не вижу". Залил, таки не работает :( Выкинул ветку else - заработало.

Вот мой код. В нем я сделал такие поправки:

1. Поправил тип previousMillis (не существенно, но что-бы "было аккуратно/правильно").
2. Выкинул ветку else  (вот это главное изменение)
3. Включил подтяжку вверх, и поменял HIGH, на LOW  (вообщем у меня кнопка подключена от пина к земле)
4. Поменял номер пина на A0  (ну просто у меня уже там кнопка стоит, лень было переподключать)
5. Вывожу в Serial, при нажатии кнопки текущие значение val  (что-бы видеть что там происходит).

unsigned long previousMillis = 0; 
int val=0; 


void setup()    
{ 
  Serial.begin(57600);

  pinMode(13, OUTPUT);         
  digitalWrite(A0,HIGH); // включил внутренюю подтяжку

} 

void loop() 

{ 
  if(digitalRead(A0)==LOW)//если кнопка нажата ...  (у меня нажатая это LOW, подтянута к питанию моя кнопка)
  { 

    if (millis() -previousMillis >500)    
    { 

      previousMillis = millis();     
      val++; 
      Serial.println(val);
    } 
  } 

  if(val>=5) 
  { 
    digitalWrite(13,!digitalRead(13));//инвертируем состояние пина 
    val=0; 
  } 


} 

2nestandart: попробуйте свой код запустить не то что у вас локально в файле, а скопируйте с форума, неужели работает? речь идет про "Рассмотрим пример с более сложным таймером"

nestandart
nestandart аватар
Offline
Зарегистрирован: 15.06.2011

>>Я не понимаю КАК оно может работать? Если оно постоянно val в ноль сбрасывает, сразу при отпускании кнопки?<<

Так и должно быть. Пока мы держим кнопку val считает до пяти. Досчитал - включил светодиод. Не успел досчитать (отпустили кнопку раньше) - сбрасывается в ноль. 

Действительно , else можно и убрать .

>>Ну может "чего-то не вижу". Залил, таки не работает<<

Вы какую прогу залили ? Из поста №27 или №1 ?

>>Nestandart про богом забытый можно сказать и о Кемерове, все зависит от того с чем сравнивать. ))<<

Я говорил о Кем.области в целом.

 

nestandart
nestandart аватар
Offline
Зарегистрирован: 15.06.2011

>>попробуйте свой код запустить не то что у вас локально в файле, а скопируйте с форума, неужели работает? <<

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

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

leshak пишет:

Чудеса да и только. Я не понимаю КАК оно может работать?

Любая программа работает, если ничего не трогать и не нажимать! МК же работает! :)

nestandart, не принимайте на свой счет, шучу просто.

 

leshak
Offline
Зарегистрирован: 29.09.2011

nestandart пишет:

>>Я не понимаю КАК оно может работать? Если оно постоянно val в ноль сбрасывает, сразу при отпускании кнопки?<<

Так и должно быть. Пока мы держим кнопку val считает до пяти. Досчитал - включил светодиод. Не успел досчитать (отпустили кнопку раньше) - сбрасывается в ноль. 

Ага. Значит я, все-таки, не правильно понял что вы хотели сделать. Мне показалось что вы пытались поймать "пять нажатий". 

Как-то слегка нетрадиционно (хотя на вкус и цвет) вы подошли к вопросу "удержания кнопки". Обычно просто засекают "время нажатия" и "время отпускания". Если разница между ними больше "то что нам нужно" - что-то делаем.

triada13
Offline
Зарегистрирован: 04.01.2013

Nestandart щас ради интереса попробовал скопировать и вставить после этого изменил только пин кнопки. не работает, либо я не так симулирую нажатие кнопки.

Подскажите каков алгоритм нажатий кнопки? длительность нажатия, и длительность паузы между нажатиями?

Вот код:

long previousMillis = 0; 
 int val=0; 

 void setup()    
 { 
        
     pinMode(13, OUTPUT);         
     pinMode(9, INPUT);  
         
 } 

 void loop() 

 { 
     if(digitalRead(9)==HIGH)//если кнопка нажата ... 
     { 
         
      if (millis() -previousMillis >500)    
     { 
        previousMillis = millis();     
        val++; 
     } 
     } 
     else 
     { 
       val=0; 
     } 
        
     if(val>=5) 
     { 
       digitalWrite(13,!digitalRead(13));//инвертируем состояние пина 
       val=0; 
     } 
        
        
 } 
 

 

nestandart
nestandart аватар
Offline
Зарегистрирован: 15.06.2011

С заказчиками такое сплошь и рядом. Скинешь готовую программу, отлаженую на железе. Он зальет на свое идентичное железо.

Сначала нормально, через полдня начинается. "Что то глючит" "Сначала работало а потом нет". Начинаются качели.

"Что делали"  "Как подключали" и т.д. Ответ один - "ничего не делал , не знаю". Начинаем железо , буквально , по дорожкам прозванивать. Все нормально. Потом просишь его скинуть ТУ программу , которую ОН ШЬЕТ. И начинается "Найди десять отличий" от оригинала. Находишь. Спрашиваешь "Зачем в программу лез" ? Обычно сознаются извиняются. Но бывают и такие что "Не видел , не знаю" и точка.

nestandart
nestandart аватар
Offline
Зарегистрирован: 15.06.2011

>>каков алгоритм нажатий кнопки? длительность нажатия, и длительность паузы между нажатиями?<<

Нажимаем, держим пять секунд - загорается. Отпускаем (на любой промежуток времени) - горит. Опять нажимаем , держим - гаснет. И т.д.

Я не работаю с симуляторами так что не знаю. Но разве он может эмулировать  удержание кнопки ?

leshak
Offline
Зарегистрирован: 29.09.2011

leshak пишет:

Как-то слегка нетрадиционно (хотя на вкус и цвет) вы подошли к вопросу "удержания кнопки". Обычно просто засекают "время нажатия" и "время отпускания". Если разница между ними больше "то что нам нужно" - что-то делаем.

Что-бы небыть голословным, вот мой вариант "переключаем светик при удержании 5-ть секунд":

 

// Подключение: 
//  кнопка соединяет пин A0 и землю. Без внешник резисторов.

unsigned  long pressTime = 0;  // тут будем запоминать когда произошло нажатие кнопки

bool prevButtonState;
int val=0; 

void setup()    
{ 

  pinMode(13, OUTPUT);         
  digitalWrite(A0,HIGH); // включаем подтяжку к питанию

} 

void loop() 

{ 
  bool buttonState=digitalRead(A0)==LOW; // читаем кнопку
  
  if(!prevButtonState && buttonState){ // была не нажата, стала нажата
     pressTime=millis();
  }
  
  if(!buttonState)pressTime=0; // при отпускании кнопки - сразу останавливаем осчет
  
  if(pressTime && (millis()-pressTime>5000)){ // если с момента нажатия прошло более 5-ти секунд
    digitalWrite(13,!digitalRead(13));//инвертируем состояние пина
    pressTime=0; // останавливаем отсчет что-бы не переключить несколько раз по одному нажатию 
  }
  
  
  prevButtonState=buttonState; // запомнили "прошлое" состояние кнопки

} 

А в вашем варианте - не ясно зачем этот счетчик val++ вооще нужен. Ну просто увеличить интервал от 0.5 до 5-ти секунд и прямо там внутри - менять состояние пина.

nestandart
nestandart аватар
Offline
Зарегистрирован: 15.06.2011

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

Вот вам ценная информация. 

Слышали про компанию freeduino ? Если нет то они выпускают платы клоны ардуино , плюс торгуют некоторыми сопутствующими товарами.

Так вот это Кемеровская компания. Вот вам сайт http://www.freeduino.ru/arduino/index.html. Там в контактах телефон. Звоните и договариваетесь о компонентах , месте/времени  встречи и т.д.  Я думаю что съездить в Кемерово явно быстрей и лучше чем ждать несколько недель.

nestandart
nestandart аватар
Offline
Зарегистрирован: 15.06.2011

>>Может что то симулятор чудит? Хотя вы намекнули про ошибку, значит иду курить код.<<

Но код в вашем посте №41 правильный. Вы скопировали его с первого поста ?

Просто найдите разницу между кодом из поста №27  и кодом из поста №1.

triada13
Offline
Зарегистрирован: 04.01.2013

Nestandart проблематично смотаться с Челябы до Кемерово, всетаки 1500 км. Да с 41 поста, но и он не пашет тоже.

Leshak в вашем коде помоему ошибка, во всяком случае дуиновский редактор ругается.

triada13
Offline
Зарегистрирован: 04.01.2013

Походу не видит симулятор нажатия кнопки, надо завязывать с симулятором, и всетаки дождаться дуинку.

leshak
Offline
Зарегистрирован: 29.09.2011

nestandart пишет:

leshak, ваша программа работает , но показывать ее новичку не стоит.

IMHO стоит. Иначе потом дикие проблемы с пониманием отлавливания "фронта сигнала" и "спада". А нужно это - чуть ли не везде (да и "понять" без этого как ваша програма работает - тоже сложновато, "магия" получается).

Ну разве что использование pressTime одновременно и для "хранения времени" и "в качестве флага" - немного переборщил. Возможно отдельный флаг bool timerStarted=false; для этого стоило выделить в явном виде.

Можно в вещи типа if(pressTime) писать более явно if(pressTime>0).... но ведь это "обычная практика кода". Или

if(!prevState && state)

писать

if(prevState==false && state==true)

Но ведь, много примеров написанно именно так. Нужно же когда приучать к тому что в реальном инете встретится :)

Я и так удержался от того как-бы я писал в "боевом коде" :

/****************  НАСТРОЙКА СКЕТЧА ****************/
#define BUTTON_PIN A0 // тут настраиваем какая на каком пине у нас кнопка
#define USE_PULLUP  // закоментируейте эту строку если используете внешнюю подтяжку к нулю и больше ничего менять не нужно

/*************** КОНЕЦ НАСТРОЙКИ СКЕТЧА */

#ifdef USE_PULLUP
#define IS_BUTTON_PRESSED !digitalRead(BUTTON_PIN)
#else
#define IS_BUTTON_PRESSED digitalRead(BUTTON_PIN)
#endif

void setup(){
#ifdef USE_PULLUP
  digitalWrite(BUTTON_PIN,HIGH);
#endif
}


void loop(){
    if(IS_BUTTON_PRESSED){
       // что-то делаем по нажатию кнопки
    }
}

nestandart пишет:

Кстати у вас  исключена цикличность инвертации светодиода.

Вообще не понял. Особенно что такое "циличность инвертации светодиода".

Да и не понял, зачем вы делаете этот счетчик, увиличивающийся "раз в секунда", а потом проверяете что он достиг 5-ти? Не проще ли один раз "раз в пять секунд" и без счетчика?

nestandart
nestandart аватар
Offline
Зарегистрирован: 15.06.2011

>>Да и не понял, зачем вы делаете этот счетчик, увиличивающийся "раз в секунда", а потом проверяете что он достиг 5-ти?<<

Так понятнее.

>>Вообще не понял. Особенно что такое "циличность инвертации светодиода".<<

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

leshak
Offline
Зарегистрирован: 29.09.2011

nestandart пишет:

>>Да и не понял, зачем вы делаете этот счетчик, увиличивающийся "раз в секунда", а потом проверяете что он достиг 5-ти?<<

Так понятнее.

Но видимо не мне. Хотя, будем смотреть правде в глаза - мне стать на место "новичка" уже довольно трудно. Возможно вы правы.

nestandart пишет:

>>Вообще не понял. Особенно что такое "циличность инвертации светодиода".<<

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

Ага. Ясно.  Но у меня это тоже не сложно сделать. При инвертации диода делать не pressTime=0;, а pressTime=millis();   и все :) Проверил. Работает. Просто я такое поведение посчитал "нежелательным" и "задавил его" :) Но если ТЗ говорит "надо", то "нет проблемм" ;)

leshak
Offline
Зарегистрирован: 29.09.2011

triada13 пишет:

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

А вас "автомобилям" тоже учило сразу 3 челвека (помните про 7-мь нянек ;), удаленно, через форум, в темных очках ночью (это я на ваш телевизор намекаю) , да еще при отсутсвии самого автомобиля?   :)

Так шо "по началу" - оно всегда трудно.

triada13
Offline
Зарегистрирован: 04.01.2013

Нет меня не учили а посылали когда я спрашивал, иди мол читай Эльзу и не отвлекай от зарабатывания денюжги. Так что первые пять лет доходил своим умом и с помощью тех. руководства по ремонту автомобилей семейства VAG ELSA.

А насчет трудностей, ведь без них не интересно.

leshak
Offline
Зарегистрирован: 29.09.2011

triada13 пишет:

Нет меня не учили а посылали когда я спрашивал, иди мол читай Эльзу и не отвлекай от зарабатывания денюжги. Так что первые пять лет доходил своим умом и с помощью тех. руководства по ремонту автомобилей семейства VAG ELSA.

Вот. Меня тоже так учили "вот в той книге все есть" (даже без намека в какой главе). Только потому и знаю что-то ;)

nestandart
nestandart аватар
Offline
Зарегистрирован: 15.06.2011

>>Просто я такое поведение посчитал "нежелательным" и "задавил его" <<

Оно и есть не желательное. Просто у меня избавление от него (при помощи флага) описано в примерах ниже а должно было быть в этом. Пропустил.

nestandart
nestandart аватар
Offline
Зарегистрирован: 15.06.2011

По просьбе пользователя NE_XT.

 

>>А можно пример привести, задержки включения - выключения светодиода. Нажимаем кнопку....., 2-10 светодиодов включаются по порядку с задержкой например 1 секунда, ну и выключаются в обратном порядке .<<

Набросал программу последовательного включения/выключения  ряда светодиодов. Я использовал три светодиода , но можно и больше (просто лень было паять).

 

При нажатии кнопки последовательно включаются светодиоды 1 , 2 , 3  с задержкой 150мс.

При повторном нажатии светодиоды , так же последовательно , выключаютя.

При удержании кнопки ничего не происходит.

 

leshak, будьте добры почистите тему. Диалоги с triada13 можно удалить полностью. Остальное на ваше усмотрение.



int knopka=0;//переменная овечающая за состояние кнопки
int state=0;//переменная отвечающая за запуск функций ledonn и ledoff

void setup() 
{                
  
  pinMode(14, OUTPUT); //светодиод1 
  pinMode(15, OUTPUT); //светодиод2 
  pinMode(16, OUTPUT);//светодиод3     
}

void loop()
{
  
  
  
  if(digitalRead(9)&&!state&&!knopka)//если кнопка нажата, переменная state=0,
                                    // переменная knopka=0, то ...
{
 ledonn();//запускаем функцию
 delay(10);//небольшая защита от дребезга кнопки
}
 if(digitalRead(9)&&state&&!knopka)//если кнопка нажата, переменная state=1,
                                   // переменная knopka=0, то ...
{
 ledoff();//запускаем функцию
 delay(10);//небольшая защита от дребезга кнопки
}
if(!digitalRead(9))//если кнопка не нажата, то ...
{
  knopka=0;// обнуляем переменную knopka
  
}

  
}

void ledonn()//функция включения светодиодов
{
  digitalWrite(14, HIGH);//включаем светодиод 1
  delay(150);  //ждем            
 
  digitalWrite(15, HIGH);//включаем светодиод 2
  delay(150);  //ждем              
  
  digitalWrite(16, HIGH); //включаем светодиод 3
  delay(150);  //ждем              
  
   knopka=1;// присваиваем переменной значение 1
  state=1;// присваиваем переменной значение 1
  
}



void ledoff()//функция выключения светодиодов

{
  
  digitalWrite(16, LOW);//выключаем светодиод 3 
  delay(150); //ждем                
 
  digitalWrite(15, LOW);  //выключаем светодиод 2 
  delay(150); //ждем                
  
  digitalWrite(14, LOW);  //выключаем светодиод 1 
  delay(150); //ждем   

  
  knopka=1;// присваиваем переменной значение 1
  state=0;//обнуляем переменную
   
  
}

 

nestandart
nestandart аватар
Offline
Зарегистрирован: 15.06.2011

Можно и без дополнительных функций. Внутри loop.

Можно и без delay , но сейчас я этого делать не буду.


int knopka=0;//переменная овечающая за состояние кнопки
int state=0;//переменная отвечающая за запуск функций ledonn и ledoff

void setup() 
{                
  
  pinMode(14, OUTPUT); //светодиод1 
  pinMode(15, OUTPUT); //светодиод2 
  pinMode(16, OUTPUT);//светодиод3     
 
}

void loop()
{
  
 
  if(digitalRead(9)&&!state&&!knopka)//если кнопка нажата, переменная state=0,
                                    // переменная knopka=0, то ...
{
  digitalWrite(14, HIGH);//включаем светодиод 1
  delay(150);  //ждем            
 
  digitalWrite(15, HIGH);//включаем светодиод 2
  delay(150);  //ждем              
  
  digitalWrite(16, HIGH); //включаем светодиод 3
  delay(150);  //ждем              
  
   knopka=1;// присваиваем переменной значение 1
  state=1;// присваиваем переменной значение 1
 delay(10);//небольшая защита от дребезга кнопки
}





 if(digitalRead(9)&&state&&!knopka)//если кнопка нажата, переменная state=1,
                                   // переменная knopka=0, то ...
{
 
  digitalWrite(16, LOW);//выключаем светодиод 3 
  delay(150); //ждем                
 
  digitalWrite(15, LOW);  //выключаем светодиод 2 
  delay(150); //ждем                
  
  digitalWrite(14, LOW);  //выключаем светодиод 1 
  delay(150); //ждем   

  
  knopka=1;// присваиваем переменной значение 1
  state=0;//обнуляем переменную
  
 delay(10);//небольшая защита от дребезга кнопки
}

if(!digitalRead(9))//если кнопка не нажата, то ...
{
  knopka=0;// обнуляем переменную knopka
  
}
  
}

 

nestandart
nestandart аватар
Offline
Зарегистрирован: 15.06.2011

leshak, а как бы вы написали прграмму из поста №65 ?

Мне интересна оптимизация  кода ( не силен я в ней).

maksim
Offline
Зарегистрирован: 12.02.2012

Это просто оптимизация вашего кода

​byte pins[] = {14, 15, 16};

bool knopka = 0; //переменная овечающая за состояние кнопки
bool state = 0;  //переменная отвечающая за запуск функций ledonn и ledoff

void setup() 
{                
  for(char i = 0; i < 3; i++) pinMode(pins[i], OUTPUT); 
}

void loop()
{
  if(digitalRead(9) && !knopka)
  {
    state = !state;  
    Leds(state);    
    knopka = 1;
  }
  if(!digitalRead(9) && knopka) knopka = 0;
}


void Leds(bool state_leds) 
{
  if(state_leds){
    for(char i = 0; i < 3; i++)
    {
      digitalWrite(pins[i], HIGH);
      delay(150);  //ждем            
    }
  }
  else
  {
    for(char i = 2; i >= 0; i--)
    {
      digitalWrite(pins[i], LOW);
      delay(150);  //ждем            
    }
  }
}

 

nestandart
nestandart аватар
Offline
Зарегистрирован: 15.06.2011

maksim, компилятор жутко матюгается на вашу программу.