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

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

Прям уж жутко... вместо i опечатка l, перекопируйте еще раз.

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

Мне интересно, почему народ не использует переменные, а вместо этого, например, читает из порта дважды?

Аналогично, постоянно используют конструкции millis() в сравнениях, потом снова считывают millis().

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

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

Например:

void loop()
{
  unsigned long l_current_millis = millis();
  boolean l_btn_pressed = ( digitalRead( 9 ) == HIGH );
  if( !l_btn_pressed )
  {
    ...
    lastMillis = l_current_millis;
  }
  ...
  if( l_btn_pressed )
  {
    ...
    lastMillis = l_current_millis;
  }
}

Понятно, что иногда это нужно (читать несколько раз), однако вылавливать такие глюки бывает очень сложно.

Понятно, что можно сказать "да это тестовая прога, пофиг", но ИМХО - это плохая практика.

Не настаиваю, пишите как хотите ;)

 

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;  
    for(char i = state?0:2; state?i<3:i>=0; state?i++:i--)
    {
      digitalWrite(pins[i], state);
      delay(150);  //ждем            
    }    
    knopka = 1;
  }
  if(!digitalRead(9) && knopka) knopka = 0;
}

 

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

kisoft пишет:
Мне интересно, почему народ не использует переменные, а вместо этого, например, читает из порта дважды? ... что читая из одного и того же порта дважды, вы рискуете считать разные значения
Так ну и что с того, что разные значения, значит значение изменилось, переменные стоит использовать если действительно в этом есть необходимость. В этих примерах по этой причине глюков не будет. А "скорость" здесь не нужна.

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

Дополнение.

Включение чего либо по двойному клику.

bool state=0;//пременная состояния кнопки

unsigned long presstime=0;//пременная для хранения "Времени между нажатиями"
int val=0;//переменная для хранения количества нажатий

void setup() 
{                
 
  pinMode(13, OUTPUT);//инициализация пинов

}

void loop() 
{
  
  if(digitalRead(9)&&!state)//если кнопка нажата и state=0, то ...
  {
   
    presstime=millis();//фиксируем время нажатия
    state=1;//присваиваем переменной значение 1 
    val++;//прибавляем еденицу к val
    delay(10);//небольшая защита от дребезга
  }
  
  
  if(!digitalRead(9)&&state&&(millis()-presstime)>100)state=0;
  //если кнопка не нажата, state=1,
  //текущее время минус зафиксированое больше 100 
  //изменяя это значение можно регулировать минимальную длинну
  //пауз между нажатиями
 //обнуляем преременную state
 
 
  if(val&&(millis()-presstime)>1000)//если val больше 0,
  //текущее время минус зафиксировано больше 1000
  //изменяя это значение можно регулировать 
  //максимальное время между нажатиями
  {
  presstime=0;//обнуляем переменную
  val=0;//обнуляем переменную
  }
  
 
  if(val>1)//если переменная больше 1 или равна 2
  //изменяя это значение можно увеличивать количество нажатий
  {
    digitalWrite(13,!digitalRead(13));//инвертируем состояние пина
  
    presstime=0;//обнуляем переменную
    val=0;//обнуляем переменную
  }
  
  
}

 

Dmitry23
Offline
Зарегистрирован: 16.09.2012

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; 
     } 
        
        
 } 
 

Вот этот код из первого сообщения в этой теме! 

подскажите пожалуйста в 18 строке в if часте выражения есть число 500, как я понял это по сути время в миллисекундах

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

я ставлю вместо 500 к примеру  180000 и и в 29 строке меняю значение с 5 на 2

Запускаю программу и засекаю время проходит примерно 45 секунд и срабатывает отключение!!!

что я делаю не так??

 

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

Dmitry23 пишет:

что я делаю не так??

Показываете чужой код вместо своего.

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

Не ту перемеменную изменяете. Вот так будет работать.

Инвертация пина каждые три минуты.

 

long previousMillis = 0; 
 int val=0; 

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

 void loop() 

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

 

Dmitry23
Offline
Зарегистрирован: 16.09.2012

Большое спасибо за помощь все работает как надо!!!

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

Dmitry23 пишет:

А все потому что в моем коде много лишнего и для отражения сути проблемы с которой я столкнулся и была скопирована часть кода из этой темы!!!

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

Могу вас заверить на все 100% что данный код, если нажата кнопка, включит/выключит светодиод не через 45 секунд, а ровно через 6 минут. Поэтому показав пример рабочего кода, вместо своего, вы сделали все для того что бы вам никто не смог помочь.

long previousMillis = 0; 
int val = 0; 

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

void loop() 

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

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

Dmitry23
Offline
Зарегистрирован: 16.09.2012

для того чтобы все прояснилось привожу свой вариант кода!!!



const int ACCPin =  9; //контакт подключения реле АСС
const int passengerPin = 6; // контакт контроля нахождения людей в салоне
const int doorPin = 5; // контакт контроля состояния тригеров дверей
const int fuelPumpPin = 7; //контакт контроля состояния бензонасоса
int interval2 = 1000;
int regim = 0;
int flag = 0;
unsigned long pvMillis = 0;
int val=0; 


//переменные
int passenger = 0; //переменная для хранения данных с контакта контроля нахождения людей в салоне
int door = 0;//переменная для хранения данных с контакта контроля состояния тригеров дверей
int fuelPump = 0;//переменная для хранения данных с контакта реле бензонасоса
void setup() {
  // задаем режим выхода для порта, подключенного к реле
  
  pinMode(ACCPin, OUTPUT);
  // задаем режим входа для портов подключенных к кнопкам и датчикам
  pinMode (passengerPin, INPUT);
  pinMode (doorPin, INPUT);
  pinMode (fuelPumpPin, INPUT);
}
 
void loop()
{
  // код АСС

  passenger = digitalRead (passengerPin); //сохраняем состояние с контакта контроля пассажиров в переменную
  door = digitalRead (doorPin); //сохраняем состояние с контакта контроля тригеров дверей в переменную
  
  if (door == HIGH && flag == 0) //если дверь открыта , ТО
  {
    regim ++;
    flag = 1;
    if(regim>2)
   {
    regim = 1;
   } 
  }
  if(door == LOW  && flag == 1)
  {
    flag = 0;
  }
  if(regim == 1)
  {
    if(passenger==HIGH)
    {
      digitalWrite(ACCPin, HIGH);
    }
    if(passenger == LOW && fuelPump == LOW )
    {
      unsigned long curMillis = millis();
     if(curMillis - pvMillis > interval2) 
     {
       pvMillis = curMillis;  
       val ++ ;
      }
    } 
    else
    {
      val = 0;
    }
    if(val >=180 )
    {
      digitalWrite(ACCPin, LOW);
    }
  }
  if(regim == 2)
  {
    if(passenger == LOW && fuelPump == LOW )
    {
      unsigned long curMillis = millis();
     if(curMillis - pvMillis > interval2) 
     {
       pvMillis = curMillis;  
       val ++ ;
     
      }
    } 
    else
    {
      val = 0;
    }
    if(val >=300)
    {
      digitalWrite(ACCPin, LOW);
    }
  }  

а было вот так

const int ACCPin =  9; //контакт подключения реле АСС
const int passengerPin = 6; // контакт контроля нахождения людей в салоне
const int doorPin = 5; // контакт контроля состояния тригеров дверей
const int fuelPumpPin = 7; //контакт контроля состояния бензонасоса
int interval2 = 180000;
int regim = 0;
int flag = 0;
unsigned long pvMillis = 0;
int val=0; 


//переменные
int passenger = 0; //переменная для хранения данных с контакта контроля нахождения людей в салоне
int door = 0;//переменная для хранения данных с контакта контроля состояния тригеров дверей
int fuelPump = 0;//переменная для хранения данных с контакта реле бензонасоса
void setup() {
  // задаем режим выхода для порта, подключенного к реле
  
  pinMode(ACCPin, OUTPUT);
  // задаем режим входа для портов подключенных к кнопкам и датчикам
  pinMode (passengerPin, INPUT);
  pinMode (doorPin, INPUT);
  pinMode (fuelPumpPin, INPUT);
}
 
void loop()
{
  // код АСС

  passenger = digitalRead (passengerPin); //сохраняем состояние с контакта контроля пассажиров в переменную
  door = digitalRead (doorPin); //сохраняем состояние с контакта контроля тригеров дверей в переменную
  
  if (door == HIGH && flag == 0) //если дверь открыта , ТО
  {
    regim ++;
    flag = 1;
    if(regim>2)
   {
    regim = 1;
   } 
  }
  if(door == LOW  && flag == 1)
  {
    flag = 0;
  }
  if(regim == 1)
  {
    if(passenger==HIGH)
    {
      digitalWrite(ACCPin, HIGH);
    }
    if(passenger == LOW && fuelPump == LOW )
    {
      unsigned long curMillis = millis();
     if(curMillis - pvMillis > interval2) 
     {
       pvMillis = curMillis;  
       val ++ ;
      }
    } 
    else
    {
      val = 0;
    }
    if(val >=2 )
    {
      digitalWrite(ACCPin, LOW);
    }
  }
  if(regim == 2)
  {
    if(passenger == LOW && fuelPump == LOW )
    {
      unsigned long curMillis = millis();
     if(curMillis - pvMillis > interval2) 
     {
       pvMillis = curMillis;  
       val ++ ;
     
      }
    } 
    else
    {
      val = 0;
    }
    if(val >=5)
    {
      digitalWrite(ACCPin, LOW);
    }
  }  

и срабатывала ACC LOW через 45 секунд!

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

Вам нужно почитать про типы данных, а именно про тип int, в описании которого написанно, что данный тип может хранить числа от -32768 до 32767, а вы пытаетесь в него записать 180000, поэтому нужно просто поменять в 5-й строке тип переменной interval2 на например long и все заработает.

const int ACCPin =  9; //контакт подключения реле АСС
const int passengerPin = 6; // контакт контроля нахождения людей в салоне
const int doorPin = 5; // контакт контроля состояния тригеров дверей
const int fuelPumpPin = 7; //контакт контроля состояния бензонасоса
long interval2 = 180000;
int regim = 0;
int flag = 0;
unsigned long pvMillis = 0;
int val=0; 


//переменные
int passenger = 0; //переменная для хранения данных с контакта контроля нахождения людей в салоне
int door = 0;//переменная для хранения данных с контакта контроля состояния тригеров дверей
int fuelPump = 0;//переменная для хранения данных с контакта реле бензонасоса
void setup() {
  // задаем режим выхода для порта, подключенного к реле
  
  pinMode(ACCPin, OUTPUT);
  // задаем режим входа для портов подключенных к кнопкам и датчикам
  pinMode (passengerPin, INPUT);
  pinMode (doorPin, INPUT);
  pinMode (fuelPumpPin, INPUT);
}
 
void loop()
{
  // код АСС

  passenger = digitalRead (passengerPin); //сохраняем состояние с контакта контроля пассажиров в переменную
  door = digitalRead (doorPin); //сохраняем состояние с контакта контроля тригеров дверей в переменную
  
  if (door == HIGH && flag == 0) //если дверь открыта , ТО
  {
    regim ++;
    flag = 1;
    if(regim>2)
   {
    regim = 1;
   } 
  }
  if(door == LOW  && flag == 1)
  {
    flag = 0;
  }
  if(regim == 1)
  {
    if(passenger==HIGH)
    {
      digitalWrite(ACCPin, HIGH);
    }
    if(passenger == LOW && fuelPump == LOW )
    {
      unsigned long curMillis = millis();
     if(curMillis - pvMillis > interval2) 
     {
       pvMillis = curMillis;  
       val ++ ;
      }
    } 
    else
    {
      val = 0;
    }
    if(val >=1)
    {
      digitalWrite(ACCPin, LOW);
    }
  }
  if(regim == 2)
  {
    if(passenger == LOW && fuelPump == LOW )
    {
      unsigned long curMillis = millis();
     if(curMillis - pvMillis > interval2) 
     {
       pvMillis = curMillis;  
       val ++ ;
     
      }
    } 
    else
    {
      val = 0;
    }
    if(val >=5)
    {
      digitalWrite(ACCPin, LOW);
    }
  }  

Так же если вы хотите 3 минуты, а не 6 то и условие в 65 строке if(val >=2) нужно поменять на if(val >=1).

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

nestandart пишет:

leshak, не чистите пока тему. Мне интересно как быстро triada13 найдет свою ошибку.

Прошу прощения что долго не отвечал.

Сегодня просмотрел свой код "вооруженным" глазом, и нашел свой касяк: я третий опеатор цикла if поместил во внутрь скобок первого оператора цикла if. То есть после val++; должно быть две закр. скобки "}".

 

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

Да. Именно так.

Artur1985
Offline
Зарегистрирован: 19.02.2013

Здраствуйте.
Спасибо за проделанный труд, очень полезная информация.

Делаю свои робкие шаги в освоении Arduino.
Как правильно сделать, данное решение.

Есть кнопка, и концевик (по сути, тоже кнопка).
Нажиамем и удерживаем кнопку, запускается пневмо цилинд и идет до концевика или пока кнопка не отпущена. При этом он не должен выполнять операцию 1 и операцию 3.

У меня в голове получилось такое решение, но может оно не коректно
Разнести 1,2,3 оперции по кейзам.
 

switch(action)
{
     case 1:
       break;
      case 2:
       while (digitalRead(4) == HIGH && state != HIGH)
       {
         digitalWrite(13, digitalRead(4));
       }
       break;
      case 3:
       break;       
 }

Код корявый, знаю, но сама идея правильна?
 

 

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

>>Код корявый, знаю<<

Давайте весь код.

>>но сама идея правильна?<<

Не совсем. Использование while нецелесообразно. Получается так что вся ваша программа стоит колом, пока вы не выйдете из while. Это не есть хорошо.

Artur1985
Offline
Зарегистрирован: 19.02.2013

>> Давайте весь код.

Его еще нет, пока обдумываю как сделать.
Этот набил, чтобы было понятнее.

>> Получается так что вся ваша программа стоит колом, пока вы не выйдете из while. Это не есть хорошо.
Да, я это понимаю. Но меня это не смущало, пока вы об этом не упомянули.

Переменная state, будет меняться по прерыванию от концевика. Она может не изменить из-за цикла?

>> Использование while нецелесообразно
А как это делают?
Нужно не просто включить выключить, а именно нажать и держать, пока нажата кнопка цилиндр идет.

 

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

Все это можно сделать с помощью конструкций if else.

Вы полностью весь алгоритм набросайте. ПОсмотрим что можно сделать.

Artur1985
Offline
Зарегистрирован: 19.02.2013

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

Ок, думаю, к обеду завтра напишу.

И заодно проверю, срабатывает прерывание и таймер, то, что он останавливает ход выполнения это не минус, в данном конкретном случае.

Спасибо.

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

>>Делаю свои робкие шаги в освоении Arduino.
Как правильно сделать, данное решение.<<

Вы спросили как правильно ?

 Я сказал свое мнение.

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

Я имею в виду торможение (а тем более остановку) программы. 

Artur1985
Offline
Зарегистрирован: 19.02.2013

>> Вы спросили как правильно ?
>> Я сказал свое мнение.
Наверно я не правильно выразился.

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

>> И заодно проверю, срабатывает прерывание и таймер, то, что он останавливает ход выполнения это не минус, в данном конкретном случае.
Это простое любопытсво, во мне заиграло:).

Разумеется, хочется правильно, поэтому и обратился.

 

Artur1985
Offline
Зарегистрирован: 19.02.2013

Уф, даже быстрее управился, думал уйдет день.
 

// Переменные контактов
int btnMode = 27; // Кнопка выбора режима

int btnStop = 28; // Кнопка экстренной остановки

int btnPause = 29; // Кнопка остановки

int btnStart = 30; // Кнопка старта

// Для автоматического режима
int keyFrameDown = 31; // Запуск опускания рамки
int senFrameDown = 32; // Концевик опускания рамки 32

int keyPlateForward = 33; // Запуск плиты вперед
int senPlateForward = 34; // Концевик запуска плиты вперед 34

int keyStartPlate = 35; // Включение плиты
int senPlateStartTimmer = 32; // Получение от плиты команды на запуск таймера 36

int keyPlateBack = 37; // Запуск плиты назад 
int senPlateBack = 34; // Концевик плиты назад 38

int keyBulgeOn = 39; // Включение раздува

int keyFormUp = 40; // Подъем формы
int senFormUp = 32; // Концевик подъема формы 41

int keyVacuumOn = 42; // Включение вакуума

int keyBlowingupOn = 43; // Включение раздува воздуха

int keyFrameUp = 44; // Запуск подъема рамки
int senTFrameUp = 34; // Концевик подъема рамки 45
// /Для автоматического режима
// Для ручного режима
int btnFrameDown = 22; // Кнопка опускания рамки

int btnPlateForward = 23; // Кнопка запуска плиты вперед

int btnStartPlate = 19; // Кнопка включения плиты

int btnPlateBack = 18; // Кнопка запуска плиты назад 

int btnBulgeOn = 17; // Кнопка включения раздува

int btnFormUp = 16; // Кнопка подъема формы

int btnVacuumOn = 15; // Кнопка включения вакуума

int btnBlowingupOn = 14; // Кнопка включение раздува воздуха

int btnFrameUp = 7; // Запуск подъема рамки
// /Для ручного режима
// /Переменные контактов

// Перечисления автомата
typedef enum {
  STATE_None, // Начало работы
  STATE_Start, // Старт программы + запуск опускания рамки
  STATE_WaitFrameDown, // Ждем сработки от концовика опускания рамки
  STATE_PlateForward, // Запуск плиты вперед
  STATE_WaitPlateForward, // Ждем сработки от концовика запуска плиты вперед
  STATE_StartPlate, // Включение обогрева плиты
  STATE_WaitStartPlate, // Ждем сработки окончания обогрева плиты + Отключение обогрева плиты + Запуск плиты назад 
  STATE_WaitPlateBack, // Ждем сработки от концовика запуска плиты назад + Остановка плиты назад + Включение раздува + Подъем формы
  STATE_WaitFormUp, // Ждем сработки от подъема формы + Отключение подъема формы + Отключение раздува + Включение вакумма + таймер + Отключение вакумма + Включение поддува воздуха + таймер + Отключение поддува воздуха + Запуск подъема рамки
  STATE_WaitFrameUp, // Ждем сработки от концовика подъема рамки
  STATE_End // Конец работы
 } ESTATE;
  
ESTATE state = STATE_None;
// Перечисления автомата

// Переменные COM порта
int speedCom = 9600;
// /Переменные COM порта

// Переменные
boolean currentBtnMode = LOW; // Тек. значение для кнопки выбора режима
boolean lastBtnMode = LOW; // Последние значение для кнопки выбора режима

boolean currentBtnStop = LOW; // Тек. значение для кнопки экстренной остановки
boolean lastBtnStop = LOW; // Последние значение для кнопки экстренной остановки

boolean currentBtnStart = LOW; // Тек. значение для кнопки старта
boolean lastBtnStart = LOW; // Последние значение для кнопки старта

boolean currentBtnFrameDownStatus = LOW; //  Тек. значение для кнопки опускания рамки
boolean lastBtnFrameDownStatus  = LOW; // Последние значение для кнопки опускания рамки

boolean currentBtnPlateForwardStatus = LOW; //  Тек. значение для кнопки запуска плиты вперед
boolean lastBtnPlateForwardStatus  = LOW; // Последние значение для кнопки запуска плиты вперед
// /Переменные

// Переменные таймера
int plateStartTimmerCountSec = 5; // Время в секундах, после получение от плиты команды
int vacuumOnCountSec = 5; // Время в секундах, после получение вакумма
int blowingupOnCountSec = 5;  // Время в секундах, после включения раздува воздуха

unsigned long currentPlateStartTimmer; // Считываем время, прошедшее с момента запуска программы, после получение от плиты команды
unsigned long loopPlateStartTimmer; // Считываем время, прошедшее с момента запуска таймера, после получение от плиты команды

unsigned long currentVacuumOnCountSec; // Считываем время, прошедшее с момента запуска программы, после получение вакуума
unsigned long loopVacuumOnCountSec; // Считываем время, прошедшее с момента запуска таймера, после получение вакуума

unsigned long currentBlowingupOnCountSec; // Считываем время, прошедшее с момента запуска программы, после включения раздува воздуха
unsigned long loopBlowingupOnCountSec; // Считываем время, прошедшее с момента запуска таймера, после включения раздува воздуха
// /Переменные таймера

// Настройки
void setup() 
{
  // Настраиваем контакты
  pinMode(btnMode, INPUT);  // Кнопка выбора режима
  
  pinMode(btnStop, INPUT);  // Кнопка экстренной остановки
  
  pinMode(btnPause, INPUT);  // Кнопка остановки
  
  pinMode(btnStart, INPUT);  // Кнопка старта
  
  // Для автоматического режима
  pinMode(keyFrameDown, OUTPUT);  // Запуск опускания рамки
  pinMode(senFrameDown, INPUT); // Концевик опускания рамки
  
  pinMode(keyPlateForward, OUTPUT);  // Запуск плиты вперед
  pinMode(senPlateForward, INPUT); // Концевик запуска плиты вперед
  
  pinMode(keyStartPlate, OUTPUT); // Включение плиты
  pinMode(senPlateStartTimmer, INPUT); // Получение от плиты команды на запуск таймера
  
  pinMode(keyPlateBack, OUTPUT);  // Запуск плиты назад 
  pinMode(senPlateBack, INPUT); // Концевик плиты назад 
  
  pinMode(keyBulgeOn, OUTPUT);  // Включение раздува
  
  pinMode(keyFormUp, OUTPUT);  // Подъем формы
  pinMode(senFormUp, INPUT); // Концевик подъема формы
  
  pinMode(keyVacuumOn, OUTPUT);  // Включение вакуума
  
  pinMode(keyBlowingupOn, OUTPUT);  // Включение раздува воздуха
    
  pinMode(keyFrameUp, OUTPUT);  // Запуск подъема рамки
  pinMode(senTFrameUp, INPUT); // Концевик подъема рамки
  // /Для автоматического режима
  // Для ручного режима
  pinMode(btnFrameDown, INPUT); // Кнопка опускания рамки
  
  pinMode(btnPlateForward, INPUT); // Кнопка запуска плиты вперед
 
  pinMode(btnStartPlate, INPUT); // Кнопка включения плиты

  pinMode(btnPlateBack, INPUT); // Кнопка запуска плиты назад 
  
  pinMode(btnBulgeOn, INPUT); // Кнопка включения раздува 
  
  pinMode(btnFormUp, INPUT); // Кнопка подъема формы
  
  pinMode(btnVacuumOn, INPUT); // Кнопка включения вакуума

  pinMode(btnBlowingupOn, INPUT); // Кнопка включение раздува воздуха

  pinMode(btnFrameUp, INPUT); // Запуск подъема рамки
  // /Для ручного режима
  // /Настраиваем контакты
  
  // Создаем COM объект
  Serial.begin(speedCom);  
  // /Создаем COM объект
  
  // Иницилизация
  Serial.println("Initialization"); 
  // /Иницилизация
}

// Основная программа
void loop()
{
  // Проверка нажата ли кнопка ручного режима
  if (digitalRead(btnMode) == HIGH)
  //if (digitalRead(btnMode) == LOW)
  {
    // Автоматический режим   
    switch (state) {
      // Начало работы
      case STATE_None:
        if (digitalRead(btnStart) == HIGH)
        {
          state = STATE_Start;
          Serial.println("Start Auto Cycle"); // Запуск автоматического режима
        }
        break;
      case STATE_Start:
        digitalWrite(keyFrameDown, HIGH); // Старт программы + запуск опускания рамки
        state = STATE_WaitFrameDown;
        Serial.println("A_1");
        break;
      case STATE_WaitFrameDown:
        if (digitalRead(senFrameDown) == HIGH)
        {
          digitalWrite(keyFrameDown, LOW); // Остановка опускания рамки
          state = STATE_PlateForward;
          Serial.println("A_2");
        }
        break;
      case STATE_PlateForward:
        digitalWrite(keyPlateForward, HIGH); // Запуск плиты вперед
        state = STATE_WaitPlateForward;
        Serial.println("A_3");
        break;
      case STATE_WaitPlateForward:
        if (digitalRead(senPlateForward) == HIGH)
        {
          digitalWrite(keyPlateForward, LOW);  // Остановка плиты вперед
          state = STATE_StartPlate;
          Serial.println("A_4");
        }
        break; 
      case STATE_StartPlate:
        digitalWrite(keyStartPlate, HIGH);  // Включение обогрева плиты
        state = STATE_WaitStartPlate;
        Serial.println("A_5");
        break;
      case STATE_WaitStartPlate:
        if (digitalRead(senPlateStartTimmer) == HIGH)
        {
          // Включаю таймер
          SetTimmerOnMillis(currentPlateStartTimmer, loopPlateStartTimmer, plateStartTimmerCountSec);
          
          digitalWrite(keyStartPlate, LOW); // Отключение обогрева плиты
          digitalWrite(keyPlateBack, HIGH); // Запуск плиты назад 
          
          state = STATE_WaitPlateBack;
          Serial.println("A_6");
        }
        break;
      case STATE_WaitPlateBack:
        if (digitalRead(senPlateBack) == HIGH)
        {
          digitalWrite(keyPlateBack, LOW); // Остановка плиты назад 
          digitalWrite(keyBulgeOn, HIGH); // Включение раздува
          digitalWrite(keyFormUp, HIGH); // Подъем формы
          
          state = STATE_WaitFormUp;
          Serial.println("A_7");
        }
        break;
      case STATE_WaitFormUp:
        if (digitalRead(senFormUp) == HIGH)
        {
          digitalWrite(keyFormUp, LOW); // Отключение подъема формы
          digitalWrite(keyBulgeOn, LOW); // Отключение раздува
          digitalWrite(keyVacuumOn, HIGH); // Включение вакумма
          
          // Включаю таймер
          SetTimmerOnMillis(currentVacuumOnCountSec, loopVacuumOnCountSec, vacuumOnCountSec);
          
          digitalWrite(keyVacuumOn, LOW); // Отключение вакумма
          digitalWrite(keyBlowingupOn, HIGH); // Включение поддува воздуха
          
          // Включаю таймер
          SetTimmerOnMillis(currentBlowingupOnCountSec, loopBlowingupOnCountSec, blowingupOnCountSec);
          
          digitalWrite(keyBlowingupOn, LOW); // Отключение поддува воздуха    
          digitalWrite(keyFrameUp, HIGH);  // Запуск подъема рамки
          
          state = STATE_WaitFrameUp;
          Serial.println("A_8");
        }
        break;
      case STATE_WaitFrameUp:
        if (digitalRead(senTFrameUp) == HIGH)
        {
          digitalWrite(keyFrameUp, LOW);  // Отключение подъема рамки
          
          state = STATE_None;
          Serial.println("End Auto Cycle");
        }
        break;  
    }
  }
  else if (digitalRead(btnMode) == LOW)
  {
    // Ручной режим
    if (digitalRead(btnFrameDown) == HIGH && digitalRead(senFrameDown) != HIGH)
    {
      digitalWrite(keyFrameDown, HIGH); // Запуск опускания рамки
      Serial.println("M_1");
    }
    else if ((digitalRead(btnFrameDown) == LOW || digitalRead(senFrameDown) == HIGH))
    {
      if (digitalRead(keyFrameDown) == HIGH)
      {
        digitalWrite(keyFrameDown, LOW); // Остановка опускания рамки
        Serial.println("M_1_1");
      }
    }
    
    if (digitalRead(btnPlateForward) == HIGH && digitalRead(senPlateForward) != HIGH)
    {
      digitalWrite(keyPlateForward, HIGH); // Запуск опускания рамки
      Serial.println("M_2");
    }
    else if ((digitalRead(btnPlateForward) == LOW || digitalRead(senPlateForward) == HIGH))
    {
      if (digitalRead(keyPlateForward) == HIGH)
      {
        digitalWrite(keyPlateForward, LOW); // Остановка опускания рамки
        Serial.println("M_2_1");
      }
    }
  }
}

// Функция таймер с задержкой, вместо delay
void SetTimmerOnMillis(long currentPlateStartTimmer, long loopPlateStartTimmer, int plateStartTimmerCountSec)
{
    currentPlateStartTimmer = millis();       // считываем время, прошедшее с момента запуска программы
    loopPlateStartTimmer = currentPlateStartTimmer;  
    while (currentPlateStartTimmer <= (loopPlateStartTimmer + (plateStartTimmerCountSec * 1000)))
    {
      currentPlateStartTimmer= millis(); 
    }
}

/* Не используется */ 
// Функция удаления дребезга кнопок
boolean Debounce(boolean lastValue, int switchPin)
{
  boolean currentValue = digitalRead(switchPin);
  if (lastValue != currentValue)
  {
    long currentTime  = millis();
    long loopTime = currentTime;  
    while (currentTime <= (loopTime + 5))
    {
      currentTime = millis(); 
    }
    
    currentValue = digitalRead(switchPin);
  }
  return currentValue;
}

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

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

Сейчас коректно?

Исправил в 18.47, там была ошибка, оказывается порты с 14 по 21, как-то забавно себя ведут.
Код очень похож на C#, мне моментом стало все понятно.

Вот в электронике пока, ни чего не смылю.

 

Artur1985
Offline
Зарегистрирован: 19.02.2013

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

nestandart большое спасибо.

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

Извиняюсь , но я еще не изучал вашу программу.

Занят с срочным заказом. Посмотрю завтра.

Artur1985
Offline
Зарегистрирован: 19.02.2013
// Переменные контактов
int btnMode = 27; // Кнопка выбора режима

int btnStop = 28; // Кнопка экстренной остановки

int btnPause = 29; // Кнопка остановки

int btnStart = 30; // Кнопка старта

// Для автоматического режима
int keyFrameDown = 31; // Запуск опускания рамки
int senFrameDown = 32; // Концевик опускания рамки 32

int keyPlateForward = 33; // Запуск плиты вперед
int senPlateForward = 34; // Концевик запуска плиты вперед 34

int keyStartPlate = 35; // Включение плиты
int senPlateStartTimmer = 32; // Получение от плиты команды на запуск таймера 36

int keyPlateBack = 37; // Запуск плиты назад 
int senPlateBack = 34; // Концевик плиты назад 38

int keyBulgeOn = 39; // Включение раздува

int keyFormUp = 40; // Подъем формы
int senFormUp = 32; // Концевик подъема формы 41

int keyVacuumOn = 42; // Включение вакуума

int keyBlowingupOn = 43; // Включение раздува воздуха

int keyFrameUp = 44; // Запуск подъема рамки
int senFrameUp = 34; // Концевик подъема рамки 45
// /Для автоматического режима
// Для ручного режима
int btnFrameDown = 21; // Кнопка опускания рамки

int btnPlateForward = 20; // Кнопка запуска плиты вперед

int btnStartPlate = 19; // Кнопка включения плиты

int btnPlateBack = 18; // Кнопка запуска плиты назад

int btnBulgeOn = 17; // Кнопка включения раздува

int btnFormUp = 16; // Кнопка подъема формы 

int btnVacuumOn = 15; // Кнопка включения вакуума

int btnBlowingupOn = 14; // Кнопка включение раздува воздуха 14

int btnFrameUp = 22; // Запуск подъема рамки 7
// /Для ручного режима
// /Переменные контактов

// Перечисления автомата
typedef enum {
  STATE_None, // Начало работы
  STATE_Start, // Старт программы + запуск опускания рамки
  STATE_WaitFrameDown, // Ждем сработки от концовика опускания рамки
  STATE_PlateForward, // Запуск плиты вперед
  STATE_WaitPlateForward, // Ждем сработки от концовика запуска плиты вперед
  STATE_StartPlate, // Включение обогрева плиты
  STATE_WaitStartPlate, // Ждем сработки окончания обогрева плиты + Отключение обогрева плиты + Запуск плиты назад 
  STATE_WaitPlateBack, // Ждем сработки от концовика запуска плиты назад + Остановка плиты назад + Включение раздува + Подъем формы
  STATE_WaitFormUp, // Ждем сработки от подъема формы + Отключение подъема формы + Отключение раздува + Включение вакуума + таймер + Отключение вакуума + Включение поддува воздуха + таймер + Отключение поддува воздуха + Запуск подъема рамки
  STATE_WaitFrameUp, // Ждем сработки от концовика подъема рамки
  STATE_End // Конец работы
 } ESTATE;
  
ESTATE state = STATE_None;
// Перечисления автомата

// Переменные COM порта
int speedCom = 9600;
// /Переменные COM порта

// Переменные
boolean currentBtnMode = LOW; // Тек. значение для кнопки выбора режима
boolean lastBtnMode = LOW; // Последние значение для кнопки выбора режима

boolean currentBtnStop = LOW; // Тек. значение для кнопки экстренной остановки
boolean lastBtnStop = LOW; // Последние значение для кнопки экстренной остановки

boolean currentBtnStart = LOW; // Тек. значение для кнопки старта
boolean lastBtnStart = LOW; // Последние значение для кнопки старта

boolean flagStartPlate = LOW; // Флаг хранения состояния кнопки включение плиты

boolean currentBtnBulgeOn = LOW; // Тек. значение для кнопки раздува
boolean lastBtnBulgeOn = LOW; // Последние значение для кнопки раздува
boolean flagBulgeOn = LOW; // Флаг хранения состояния кнопки раздува

boolean currentBtnVacuumOn = LOW; // Тек. значение для кнопки вакуума
boolean lastBtnVacuumOn = LOW; // Последние значение для кнопки вакуума
boolean flagVacuumOn = LOW; // Флаг хранения состояния кнопки вакуума

boolean currentBtnBlowingupOn = LOW; // Тек. значение для кнопки раздува воздуха
boolean lastBtnBlowingupOn = LOW; // Последние значение для кнопки раздува воздуха
boolean flagBlowingupOn = LOW; // Флаг хранения состояния кнопки раздува воздуха
// /Переменные

// Переменные таймера
int plateStartTimmerCountSec = 5; // Время в секундах, после получение от плиты команды
int vacuumOnCountSec = 5; // Время в секундах, после получение вакуума
int blowingupOnCountSec = 5;  // Время в секундах, после включения раздува воздуха

unsigned long currentPlateStartTimmer; // Считываем время, прошедшее с момента запуска программы, после получение от плиты команды
unsigned long loopPlateStartTimmer; // Считываем время, прошедшее с момента запуска таймера, после получение от плиты команды

unsigned long currentVacuumOnCountSec; // Считываем время, прошедшее с момента запуска программы, после получение вакуума
unsigned long loopVacuumOnCountSec; // Считываем время, прошедшее с момента запуска таймера, после получение вакуума

unsigned long currentBlowingupOnCountSec; // Считываем время, прошедшее с момента запуска программы, после включения раздува воздуха
unsigned long loopBlowingupOnCountSec; // Считываем время, прошедшее с момента запуска таймера, после включения раздува воздуха
// /Переменные таймера

// Настройки
void setup() 
{
  // Настраиваем контакты
  pinMode(btnMode, INPUT);  // Кнопка выбора режима
  
  pinMode(btnStop, INPUT);  // Кнопка экстренной остановки
  
  pinMode(btnPause, INPUT);  // Кнопка остановки
  
  pinMode(btnStart, INPUT);  // Кнопка старта
  
  // Для автоматического режима
  pinMode(keyFrameDown, OUTPUT);  // Запуск опускания рамки
  pinMode(senFrameDown, INPUT); // Концевик опускания рамки
  
  pinMode(keyPlateForward, OUTPUT);  // Запуск плиты вперед
  pinMode(senPlateForward, INPUT); // Концевик запуска плиты вперед
  
  pinMode(keyStartPlate, OUTPUT); // Включение плиты
  pinMode(senPlateStartTimmer, INPUT); // Получение от плиты команды на запуск таймера
  
  pinMode(keyPlateBack, OUTPUT);  // Запуск плиты назад 
  pinMode(senPlateBack, INPUT); // Концевик плиты назад 
  
  pinMode(keyBulgeOn, OUTPUT);  // Включение раздува
  
  pinMode(keyFormUp, OUTPUT);  // Подъем формы
  pinMode(senFormUp, INPUT); // Концевик подъема формы
  
  pinMode(keyVacuumOn, OUTPUT);  // Включение вакуума
  
  pinMode(keyBlowingupOn, OUTPUT);  // Включение раздува воздуха
    
  pinMode(keyFrameUp, OUTPUT);  // Запуск подъема рамки
  pinMode(senFrameUp, INPUT); // Концевик подъема рамки
  // /Для автоматического режима
  // Для ручного режима
  pinMode(btnFrameDown, INPUT); // Кнопка опускания рамки
  
  pinMode(btnPlateForward, INPUT); // Кнопка запуска плиты вперед
 
  pinMode(btnStartPlate, INPUT); // Кнопка включения плиты

  pinMode(btnPlateBack, INPUT); // Кнопка запуска плиты назад 
  
  pinMode(btnBulgeOn, INPUT); // Кнопка включения раздува 
  
  pinMode(btnFormUp, INPUT); // Кнопка подъема формы
  
  pinMode(btnVacuumOn, INPUT); // Кнопка включения вакуума

  pinMode(btnBlowingupOn, INPUT); // Кнопка включение раздува воздуха

  pinMode(btnFrameUp, INPUT); // Запуск подъема рамки
  // /Для ручного режима
  // /Настраиваем контакты
  
  // Создаем COM объект
  Serial.begin(speedCom);  
  // /Создаем COM объект
  
  // Иницилизация
  Serial.println("Initialization"); 
  // /Иницилизация
}

// Основная программа
void loop()
{
  // Проверка нажата ли кнопка ручного режима
  if (digitalRead(btnMode) == HIGH)
  //if (digitalRead(btnMode) == LOW)
  {
    // Автоматический режим   
    switch (state) {
      // Начало работы
      case STATE_None:
        if (digitalRead(btnStart) == HIGH)
        {
          state = STATE_Start;
          Serial.println("Start Auto Cycle"); // Запуск автоматического режима
        }
        break;
      case STATE_Start:
        digitalWrite(keyFrameDown, HIGH); // Старт программы + запуск опускания рамки
        state = STATE_WaitFrameDown;
        Serial.println("A_1");
        break;
      case STATE_WaitFrameDown:
        if (digitalRead(senFrameDown) == HIGH)
        {
          digitalWrite(keyFrameDown, LOW); // Остановка опускания рамки
          state = STATE_PlateForward;
          Serial.println("A_2");
        }
        break;
      case STATE_PlateForward:
        digitalWrite(keyPlateForward, HIGH); // Запуск плиты вперед
        state = STATE_WaitPlateForward;
        Serial.println("A_3");
        break;
      case STATE_WaitPlateForward:
        if (digitalRead(senPlateForward) == HIGH)
        {
          digitalWrite(keyPlateForward, LOW);  // Остановка плиты вперед
          state = STATE_StartPlate;
          Serial.println("A_4");
        }
        break; 
      case STATE_StartPlate:
        digitalWrite(keyStartPlate, HIGH);  // Включение обогрева плиты
        state = STATE_WaitStartPlate;
        Serial.println("A_5");
        break;
      case STATE_WaitStartPlate:
        if (digitalRead(senPlateStartTimmer) == HIGH)
        {
          // Включаю таймер
          SetTimmerOnMillis(currentPlateStartTimmer, loopPlateStartTimmer, plateStartTimmerCountSec);
          
          digitalWrite(keyStartPlate, LOW); // Отключение обогрева плиты
          digitalWrite(keyPlateBack, HIGH); // Запуск плиты назад 
          
          state = STATE_WaitPlateBack;
          Serial.println("A_6");
        }
        break;
      case STATE_WaitPlateBack:
        if (digitalRead(senPlateBack) == HIGH)
        {
          digitalWrite(keyPlateBack, LOW); // Остановка плиты назад 
          digitalWrite(keyBulgeOn, HIGH); // Включение раздува
          digitalWrite(keyFormUp, HIGH); // Подъем формы
          
          state = STATE_WaitFormUp;
          Serial.println("A_7");
        }
        break;
      case STATE_WaitFormUp:
        if (digitalRead(senFormUp) == HIGH)
        {
          digitalWrite(keyFormUp, LOW); // Отключение подъема формы
          digitalWrite(keyBulgeOn, LOW); // Отключение раздува
          digitalWrite(keyVacuumOn, HIGH); // Включение вакуума
          
          // Включаю таймер
          SetTimmerOnMillis(currentVacuumOnCountSec, loopVacuumOnCountSec, vacuumOnCountSec);
          
          digitalWrite(keyVacuumOn, LOW); // Отключение вакуума
          digitalWrite(keyBlowingupOn, HIGH); // Включение поддува воздуха
          
          // Включаю таймер
          SetTimmerOnMillis(currentBlowingupOnCountSec, loopBlowingupOnCountSec, blowingupOnCountSec);
          
          digitalWrite(keyBlowingupOn, LOW); // Отключение поддува воздуха    
          digitalWrite(keyFrameUp, HIGH);  // Запуск подъема рамки
          
          state = STATE_WaitFrameUp;
          Serial.println("A_8");
        }
        break;
      case STATE_WaitFrameUp:
        if (digitalRead(senFrameUp) == HIGH)
        {
          digitalWrite(keyFrameUp, LOW);  // Отключение подъема рамки
          
          state = STATE_None;
          Serial.println("End Auto Cycle");
        }
        break;  
    }
  }
  else if (digitalRead(btnMode) == LOW)
  {
    // Ручной режим, отладка
    if (digitalRead(btnFrameDown) == HIGH && digitalRead(senFrameDown) != HIGH)
    {
      digitalWrite(keyFrameDown, HIGH); // Запуск опускания рамки
      Serial.println("M_1");
    }
    else if ((digitalRead(btnFrameDown) == LOW || digitalRead(senFrameDown) == HIGH))
    {
      if (digitalRead(keyFrameDown) == HIGH)
      {
        digitalWrite(keyFrameDown, LOW); // Остановка опускания рамки
        Serial.println("M_1_1");
      }
    }
    
    if (digitalRead(btnPlateForward) == HIGH && digitalRead(senPlateForward) != HIGH)
    {
      digitalWrite(keyPlateForward, HIGH); // Запуск плиты вперед
      Serial.println("M_2");
    }
    else if ((digitalRead(btnPlateForward) == LOW || digitalRead(senPlateForward) == HIGH))
    {
      if (digitalRead(keyPlateForward) == HIGH)
      {
        digitalWrite(keyPlateForward, LOW); // Остановка плиты вперед
        Serial.println("M_2_1");
      }
    }
    
    if (flagStartPlate == LOW && digitalRead(btnStartPlate) == HIGH && digitalRead(senPlateStartTimmer) != HIGH)
    {
      digitalWrite(keyStartPlate, HIGH); // Включение обогрева плиты
      flagStartPlate = HIGH;
      
      Serial.println("M_3");
    }
    else if (digitalRead(senPlateStartTimmer) == HIGH)
    {
      if (flagStartPlate == HIGH && digitalRead(keyStartPlate) == HIGH)
      {
        // Включаю таймер
        SetTimmerOnMillis(currentPlateStartTimmer, loopPlateStartTimmer, plateStartTimmerCountSec);
          
        digitalWrite(keyStartPlate, LOW); // Отключение обогрева плиты
        flagStartPlate = LOW;
        
        Serial.println("M_3_1");
      }
    }
    
    if (digitalRead(btnPlateBack) == HIGH && digitalRead(senPlateBack) != HIGH)
    {
      digitalWrite(keyPlateBack, HIGH); // Запуск плиты назад 
      Serial.println("M_4");
    }
    else if ((digitalRead(btnPlateBack) == LOW || digitalRead(senPlateBack) == HIGH))
    {
      if (digitalRead(keyPlateBack) == HIGH)
      {
        digitalWrite(keyPlateBack, LOW); // Остановка плиты назад 
        Serial.println("M_4_1");
      }
    }
    
    currentBtnBulgeOn = Debounce(lastBtnBulgeOn, btnBulgeOn);
    if(currentBtnBulgeOn == HIGH && flagBulgeOn == LOW)
    { 
       flagBulgeOn = HIGH;       
    } 
       
    if(currentBtnBulgeOn == LOW && flagBulgeOn == HIGH)
    { 
        digitalWrite(keyBulgeOn, !digitalRead(keyBulgeOn)); // Включаем или отключаем раздув
        if (digitalRead(keyBulgeOn) == HIGH)
        {
          Serial.println("M_5");
        }
        else 
        {
          Serial.println("M_5_1");
        }
        flagBulgeOn = LOW;
    }
   
    if (digitalRead(btnFormUp) == HIGH && digitalRead(senFormUp) != HIGH)
    {
      digitalWrite(keyFormUp, HIGH); // Запуск подъема формы
      Serial.println("M_6");
    }
    else if ((digitalRead(btnFormUp) == LOW || digitalRead(senFormUp) == HIGH))
    {
      if (digitalRead(keyFormUp) == HIGH)
      {
        digitalWrite(keyFormUp, LOW); // Отключение подъема формы
        Serial.println("M_6_1");
      }
    }
    
    currentBtnVacuumOn = Debounce(lastBtnVacuumOn, btnVacuumOn);
    if(currentBtnVacuumOn == HIGH && flagVacuumOn == LOW)
    { 
       flagVacuumOn = HIGH;       
    } 
       
    if(currentBtnVacuumOn == LOW && flagVacuumOn == HIGH)
    { 
        digitalWrite(keyVacuumOn, !digitalRead(keyVacuumOn)); // Включаем или отключаем вакуума
        if (digitalRead(keyVacuumOn) == HIGH)
        {
          Serial.println("M_7");
        }
        else 
        {
          Serial.println("M_7_1");
        }
        flagVacuumOn = LOW;
    }
    
    currentBtnBlowingupOn = Debounce(lastBtnBlowingupOn, btnBlowingupOn);
    if(currentBtnBlowingupOn == HIGH && flagBlowingupOn == LOW)
    { 
       flagBlowingupOn = HIGH;       
    } 
       
    if(currentBtnBlowingupOn == LOW && flagBlowingupOn == HIGH)
    { 
        digitalWrite(keyBlowingupOn, !digitalRead(keyBlowingupOn)); // Включаем или отключаем вакуума
        if (digitalRead(keyBlowingupOn) == HIGH)
        {
          Serial.println("M_8");
        }
        else 
        {
          Serial.println("M_8_1");
        }
        flagBlowingupOn = LOW;
    }
    
    if (digitalRead(btnFrameUp) == HIGH && digitalRead(senFrameUp) != HIGH)
    {
      digitalWrite(keyFrameUp, HIGH); // Запуск подъема рамки
      Serial.println("M_9");
    }
    else if ((digitalRead(btnFormUp) == LOW || digitalRead(senFrameUp) == HIGH))
    {
      if (digitalRead(keyFrameUp) == HIGH)
      {
        digitalWrite(keyFrameUp, LOW); // Отключение подъема рамки  
        Serial.println("M_9_1");
      }
    }
  }
}

// Функция таймер с задержкой, вместо delay
void SetTimmerOnMillis(long currentPlateStartTimmer, long loopPlateStartTimmer, int plateStartTimmerCountSec)
{
    currentPlateStartTimmer = millis();       // считываем время, прошедшее с момента запуска программы
    loopPlateStartTimmer = currentPlateStartTimmer;  
    while (currentPlateStartTimmer <= (loopPlateStartTimmer + (plateStartTimmerCountSec * 1000)))
    {
      currentPlateStartTimmer= millis(); 
    }
}

// Функция удаления дребезга кнопок
boolean Debounce(boolean lastValue, int switchPin)
{
  boolean currentValue = digitalRead(switchPin);
  if (lastValue != currentValue)
  {
    long currentTime  = millis();
    long loopTime = currentTime;  
    while (currentTime <= (loopTime + 5))
    {
      currentTime = millis(); 
    }
    
    currentValue = digitalRead(switchPin);
  }
  return currentValue;
}

Конечное решение на сегодняшний день. Еще появится ручной режим, но это все после того, как станок будет сделан в металле . Может еще какие-то удобства для оператора.

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

Всем привет!

Народ, подскажите, лучше программно защищаться от дребезга или использовать кондер параллельно кнопке?

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

Мое мнение, лучше сделать защиту от дребезга аппаратно, тогда для программы места больше будет.

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

Т.е. кондера параллельно кнопке достаточно? Или надо мастрячить как тут http://creatiff.realax.ru/?cat=spmikro&page=smikr23 ?

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

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

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

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

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

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

А если куча кнопок - триггеры, обвязка.  Места на плате займут много и мороки прибавят.

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

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

Всё же, разъясните, для аппаратного подавления дребезга какую схему применять?

nik
Offline
Зарегистрирован: 02.05.2013

Всем привет!
изучая arduino наткнулся на проблему "дребезга кнопки". Написал не большой sketch на две тактовые кнопки и две led. Впрочем посмотрите здесь пожалуйста:

int flag=0;

int pin1=22;
int pin2=25;
int led1=28;
int led2=30;


void setup()
{
  pinMode(22,INPUT);
  pinMode(25,INPUT); 
  pinMode(28,OUTPUT);
  pinMode(30,OUTPUT);
}
void loop()
{
  if (digitalRead(22)==HIGH&&flag==0) 
  {
   digitalWrite(28,!digitalRead(28));
   flag=1;
  }
  
  if (digitalRead(22)==LOW&&flag==1)
  {
   flag=0;                                
  }
  
  
  if (digitalRead(25)==HIGH&&flag==0)
  {
   digitalWrite(30,!digitalRead(30));
   flag=2;
  }
  
  if (digitalRead(25)==LOW&&flag==2)                                       
  {
   flag=0;                                
  }
} 

На второй кнопке при быстрой перемене "включил-выключил" заметны сбои. Может кто-нибудь сможет объяснить почему так происходит. Заранее спасибо.

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

Почему происходит что? дребезг? 
Дребезг контактов

nik
Offline
Зарегистрирован: 02.05.2013

Да дребезг я так думаю. При быстрой перемене включения кнопки"pin2" второй светодиод даёт сбои. Но ведь этого не должно быть потому как я использовал переменную flag или всё таки нужно использовать функцию delay

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

В вашем примере нет антидребезга, delay() как один из вариантов устранения дребезга, посмотрите стандартный пример Debounce.

Snubist
Offline
Зарегистрирован: 18.02.2013

переменная flag не спасает от дребезга.

olegab
Offline
Зарегистрирован: 09.04.2013

nik пишет:

Всем привет!
изучая arduino наткнулся на проблему "дребезга кнопки". Написал не большой sketch на две тактовые кнопки и две led. Впрочем посмотрите здесь пожалуйста:

На второй кнопке при быстрой перемене "включил-выключил" заметны сбои. Может кто-нибудь сможет объяснить почему так происходит. Заранее спасибо.

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

примерно так нужно сделать:


#define DELAY_MS 50;

unsigned long ignoreInputs[2]={0,0};
int pin[2][2]={{22,25},{28,30}};


void setup()
{
  pinMode(pin[0][0],INPUT);
  pinMode(pin[0][1],INPUT); 
  pinMode(pin[1][0],OUTPUT);
  pinMode(pin[1][1],OUTPUT);
}
void loop()
{
  if (digitalRead(pin[0][0])==HIGH&& !ignoreInputs[0]) 
  {
   digitalWrite(pin[1][0],!digitalRead(pin[1][0]));
    ignoreInputs[0]=millis()+DELAY_MS;
  }
  if (digitalRead(pin[0][1])==HIGH&& !ignoreInputs[1]) 
  {
   digitalWrite(pin[1][1],!digitalRead(pin[1][1]));
    ignoreInputs[1]=millis()+DELAY_MS;
  }
  if(ignoreInputs[0]>=millis())ignoreInputs[0]=0;
  if(ignoreInputs[1]>=millis())ignoreInputs[1]=0;
  
} 

 

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

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

Для защиты от дребезга введите временную задержку delay(10); или millis();.

nik
Offline
Зарегистрирован: 02.05.2013

Благодарю за  многочисленную помощь. А вот ещё кое-что сам нашёл, работает безукоризненно. Только надо библиотеку "Bounce" в ардуино импортировать. Вот новый скетч:

#include <Bounce.h>
#define BUTTON1 45
#define BUTTON2 47
#define LED1 41
#define LED2 43

int ledValue1 = LOW;
int ledValue2 = LOW;


Bounce bouncer1 = Bounce( BUTTON1, 45);
Bounce bouncer2 = Bounce( BUTTON2, 47);

void setup() {
  pinMode(BUTTON1,INPUT);
  pinMode(BUTTON2,INPUT);
  pinMode(LED1,OUTPUT);
  pinMode(LED2,OUTPUT);
}

void loop() {

   if ( bouncer1.update() ) {
     if ( bouncer1.read() == HIGH) {
       if ( ledValue1 == LOW ) {
         ledValue1 = HIGH;
       } else {
         ledValue1 = LOW;
       }
       digitalWrite(LED1,ledValue1);
     }
   }
   
   if ( bouncer2.update() ) {
     if ( bouncer2.read() == HIGH) {
       if ( ledValue2 == LOW ) {
         ledValue2 = HIGH;
       } else {
         ledValue2 = LOW;
       }
       digitalWrite(LED2,ledValue2);
     }
   }
   
}

 

the_wall
Offline
Зарегистрирован: 06.06.2013

Всем привет.

Имеется Arduino Uno R3, программы компелирую и гружу через Arduino 1.5.2

Вопрос. Почему фунция setup у меня вызывается постоянно?

Вот код примера

#include <LiquidCrystal.h>
LiquidCrystal lcd(10, 11, 5, 4, 3, 2);

const int buttonPin = 9; // номер входа, подключенный к кнопке

int buttonState = 0; // переменная для хранения состояния кнопки

void setup()
{
pinMode(buttonPin, INPUT);

}

void loop()
{
buttonState = digitalRead(buttonPin);

if (buttonState == LOW) {
lcd.begin(16, 2);
lcd.print("hello, world!");
}
else {
lcd.begin(16, 2);
lcd.print("hello, world33333!");
}

}

 

Т.е. на экране у меня через раные промежутки времени происходит как бы перезагрузка.

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

Возможно кнопка подключена неправильно (БЕЗ ПОДТЯЖКИ).

Так же нужно использовать оператор lcd.clear(); иначе у вас постоянно будут выводиться ваши 33333.

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

the_wall пишет:

Вопрос. Почему фунция setup у меня вызывается постоянно?

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

the_wall пишет:

Т.е. на экране у меня через раные промежутки времени происходит как бы перезагрузка.

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

 

the_wall
Offline
Зарегистрирован: 06.06.2013

Спасибо за ответы.

Даже если тупо вывести один текст, без кнопок, т.е. так

#include <LiquidCrystal.h>

LiquidCrystal lcd(10, 11, 5, 4, 3, 2);

void setup()
{
/* Инициализируем дисплей: 2 строки по 16 символов */
lcd.begin(16, 2);
/* Выводим на дисплей традиционную фразу (: */
lcd.print("hello, world!");
}

void loop()
{

}

То на экране через равне промежутки времени после "!" появляется типа курсор, который заполняет оставшиеся 3 клетки до конца строки. А так же начинает моргать тестовый диод. Хотя на его порт я ничего не подаю.

Если дописать так

 

void loop()
{
lcd.setCursor(0, 1);
/* Выводим на дисплей число секунд, прошедших с момента старта Arduino */
lcd.print(millis() / 1000);
}

 

То получается каждые 3 секнду обновляется экран и отсчет идет заново

Snubist
Offline
Зарегистрирован: 18.02.2013

the_wall пишет:

Может проблема с самим ардуино?

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

demon969
Offline
Зарегистрирован: 24.04.2012

Прокомментируйте кто-нибудь, зачем во многих примерах в это теме инвертируют значения и как это помогает с дребезгом контактов?

// плюс защита от "дребезга" 100% - почему?

digitalWrite(13,!digitalRead(13));
       flag=1;
        //это нужно для того что бы с каждым нажатием кнопки
        //происходило только одно действие
        // плюс защита от "дребезга"  100%

         

 

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

Инвертация состояния выхода это просто действие. Вместо него может быть все что угодно. В примерах я инвертирую состояние светодиода (вкл или выкл) просто для наглядности. С фильтрацией дребезга кнопки это никик не связано (за исключением приведенной вами переменной flag).

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

Никак это от дребезга не спасает, просто никто не читал что там понаписал автор этих комментариев, не понимая по каким причинам у него отсутствует дребезг.

demon969
Offline
Зарегистрирован: 24.04.2012

Эту тему я прочитал всю, но не смог понять как помогает от дребезга?

digitalWrite(13,!digitalRead(13));
       flag=1;

 

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

Никак это от дребезга не помогает

Что не ясно из этой фразы?