Помогите ламеру

karbid
Offline
Зарегистрирован: 27.11.2011

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

void setup()
{
// выходы управления реле
pinMode(2,OUTPUT);
pinMode(3,OUTPUT);
pinMode(4,OUTPUT);
pinMode(5,OUTPUT);
pinMode(6,OUTPUT);
pinMode(7,OUTPUT);
pinMode(8,OUTPUT);
pinMode(9,OUTPUT);

// инициализация порта
Serial.begin(9600);
}

void loop()
{
byte a, b, c;
if (Serial.available() > 2) // ждем данные от плагина
{
a = Serial.read();
b = Serial.read();
c = Serial.read();
if(a == 0xFF) //если данные от плагина, то выполим команду
{
digitalWrite(b+1, (c==0x01) ? HIGH : LOW); //выполнить
} } } 

 

.c8r
.c8r аватар
Offline
Зарегистрирован: 15.11.2011

кнопку надо на pinmode(x,Input) через резистор
задержка - delay

karbid
Offline
Зарегистрирован: 27.11.2011


int ledPin = 13;                // сетодиод
int btnPin = 10;                // кнопка
int val=0;


Void setup() 
{ 
// выходы управления реле 
pinMode(2,OUTPUT); 
pinMode(3,OUTPUT); 
pinMode(4,OUTPUT); 
pinMode(5,OUTPUT); 
pinMode(6,OUTPUT); 
pinMode(7,OUTPUT); 
pinMode(8,OUTPUT); 
pinMode(9,OUTPUT);
pinMode(13,OUTPUT);
pinMode(10,INPUT);
// инициализация порта 
Serial.begin(9600); 
}

void loop() 
{ 
byte a, b, c; 
if (Serial.available() > 2) // ждем данные от плагина 
{ 
a = Serial.read(); 
b = Serial.read(); 
c = Serial.read(); 
if(a == 0xFF) //если данные от плагина, то выполим команду 
{ 
digitalWrite(b+1, (c==0x01) ? HIGH : LOW); //выполнить 
} } }
{
  val = digitalRead(btnPin);    // узнаём состояние кнопки
  if(val==HIGH)                 // кнопка нажата
  {
    digitalWrite(ledPin, HIGH); // зажигаем светодиод
    Serial.println("H");
    delay(1000000);
  }
  else                          // кнопка не нажата
  {
    digitalWrite(ledPin, LOW);  // гасим светодиод
    

karbid
Offline
Зарегистрирован: 27.11.2011

 как-то так? скобки стоят правильно?

.c8r
.c8r аватар
Offline
Зарегистрирован: 15.11.2011
int ledPin = 13;                // сетодиод
int btnPin = 10;                // кнопка
int val=0;


void setup() 
{ 
  // выходы управления реле 
  pinMode(2,OUTPUT); 
  pinMode(3,OUTPUT); 
  pinMode(4,OUTPUT); 
  pinMode(5,OUTPUT); 
  pinMode(6,OUTPUT); 
  pinMode(7,OUTPUT); 
  pinMode(8,OUTPUT); 
  pinMode(9,OUTPUT);
  pinMode(13,OUTPUT);
  pinMode(10,INPUT);
  // инициализация порта 
  Serial.begin(9600); 
}

void loop()
{
  byte a, b, c; 
  if (Serial.available() > 2){ 
  a = Serial.read(); 
    b = Serial.read(); 
    c = Serial.read(); 
    if(a == 0xFF) //если данные от плагина, то выполим команду 
    { 
    digitalWrite(b+1, (c==0x01) ? HIGH : LOW); //выполнить 
    } 
  } 

    val = digitalRead(btnPin);    // узнаём состояние кнопки
    if(val==HIGH)                 // кнопка нажата
    {
      digitalWrite(ledPin, HIGH); // зажигаем светодиод
      Serial.println("H");
      delay(1000000);
    }
    else                          // кнопка не нажата
    {
      digitalWrite(ledPin, LOW);  // гасим светодиод
    }
}
.c8r
.c8r аватар
Offline
Зарегистрирован: 15.11.2011

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

karbid
Offline
Зарегистрирован: 27.11.2011

 .c8r

Спасибо, все работает:)

 

В смысле выключить выход на реле? не понял

 

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

.c8r
.c8r аватар
Offline
Зарегистрирован: 15.11.2011

В смысле выключить выход на реле? не понял

Я криво выразился, я имел ввиду послать на ledPin (на котором висит реле) сигнал LOW, чтоб наверняка...Хотя, на новом заходе в цикл идет проверка кнопки, получается лишнее действие.

step962
Offline
Зарегистрирован: 23.05.2011

 

Цитата:

delay(1000000);

Если мой склероз мне не изменяет, то это задержка в 1000 секунд. Более 16 минут МК не будет делать НИЧЕГО. Будет тупо простаивать.

Вы обладаете достаточным терпением, чтобы ожидать реакцию на нажатие кнопки или на иное действие в течение 16 минут?

Delay - коварная функция. Ее вполне можно использовать в учебных примерах типа мигания светодиодами, однако в любых системах, где предполагается реакция на внешние воздействия (те же нажатия кнопок как наиболее простой случай) ее применение ведет к нарушениям в логике работы системы. Вы нажали кнопку, чтобы выполнить какую-то операцию, а МК в это время занимается отсчетом задержки. Ничего не происходит. Вы подержали кнопку 16 минут и всего на секунду отпустили ее, чтобы поменять палец. А МК именно в этот момент перестал отсчитывать задержку и, прочитав состояние соответствующего входа, не обнаружил этого нажатия. Быстро пробежал остальное тело цикла и снова впал в ступор на 1000 секунд. Веселенький приборчик у вас получится...

.c8r
.c8r аватар
Offline
Зарегистрирован: 15.11.2011

Цикл крутиться до нажатия кнопки. Кнопка нажата - активировались выходы и ждем...По отработке delay'я опять возвращаемся в цикл.

karbid
Offline
Зарегистрирован: 27.11.2011

 ну, в общем как я и писал кнопка служит только для зажигания света в салоне автомобиля когда больше ничего не работает. то ,что процессор в это время больше ничего не делает меня устраивает, ну и со временем я погорячился- достаточно и 20 секунд будет:)
а как теперь сделать,чтобы например когда на входе 11 появляется 5 вольт кнопка не работала?

.c8r
.c8r аватар
Offline
Зарегистрирован: 15.11.2011

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

int ledPin = 13;                // сетодиод
int btnPin = 10;                // кнопка
int val=0;


void setup() 
{ 
  // выходы управления реле 
  pinMode(2,OUTPUT); 
  pinMode(3,OUTPUT); 
  pinMode(4,OUTPUT); 
  pinMode(5,OUTPUT); 
  pinMode(6,OUTPUT); 
  pinMode(7,OUTPUT); 
  pinMode(8,OUTPUT); 
  pinMode(9,OUTPUT);
  pinMode(13,OUTPUT);
  pinMode(10,INPUT);
  // инициализация порта 
  Serial.begin(9600); 
}

void loop()
{
  byte a, b, c; 
  if (Serial.available() > 2){ 
  a = Serial.read(); 
    b = Serial.read(); 
    c = Serial.read(); 
    if(a == 0xFF) //если данные от плагина, то выполим команду 
    { 
    digitalWrite(b+1, (c==0x01) ? HIGH : LOW); //выполнить 
    } 
  } 

    val = digitalRead(btnPin);    // узнаём состояние кнопки
    if(val==HIGH && digitalRead(11)=='HIGH')
    // кнопка нажата и на 11ом пине есть напряжение
    {
      digitalWrite(ledPin, HIGH); // зажигаем светодиод
      Serial.println("H");
      delay(1000000);
    }
    else                          // кнопка не нажата
    {
      digitalWrite(ledPin, LOW);  // гасим светодиод
    }
}

 

karbid
Offline
Зарегистрирован: 27.11.2011

 спасибо огромное:)

step962
Offline
Зарегистрирован: 23.05.2011

.c8r пишет:

Цикл крутиться до нажатия кнопки. Кнопка нажата - активировались выходы и ждем...По отработке delay'я опять возвращаемся в цикл.

Так я о том и говорю: кнопку нажали и в течение всего времени задержки (а это 1000 секунд - почти 20 минут) приборчик ваш ни на что не реагирует. Только на сброс питания. А стало быть во все это время абсолютно бесполезен. 

За это время ему по последовательному каналу "Войну и мир" Льва Николаевича нашего Толстого передать можно было бы. Все четыре тома. А он ни одного символа не примет. Потому что активировал выходы и ждет.

.c8r
.c8r аватар
Offline
Зарегистрирован: 15.11.2011

И чего? =)

P/S Если ОП'у надо будет передать войну и мир, то передадим. 

step962
Offline
Зарегистрирован: 23.05.2011

.c8r пишет:

P/S Если ОП'у надо будет передать войну и мир, то передадим. 

Может быть, может быть...

Однако пока не удастся вовремя передать даже три байта команды "от плагина". Существующая версия программы после нажатия кнопки (запуска delay(1000000)) не оставляет для этого никаких шансов.

.c8r
.c8r аватар
Offline
Зарегистрирован: 15.11.2011

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

Работу со временем обсуждали в соседней ветке форума, там что-то тоже было связано с автомобилями. Понадобится микросхемка времени и обвязка к ней (я с этим пока не работал, даже советовать не буду) или брать время через wi-fi/gprs/gps.

step962
Offline
Зарегистрирован: 23.05.2011

.c8r пишет:

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

Работу со временем обсуждали в соседней ветке форума, там что-то тоже было связано с автомобилями. Понадобится микросхемка времени и обвязка к ней (я с этим пока не работал, даже советовать не буду) или брать время через wi-fi/gprs/gps.

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

По второму абзацу: микросхема RTC для этой цели не нужна. Достаточно в цикле вызывать функцию Millis() и из возвращенного значения вычитать значение, сохраненное в момент нажатия на кнопку. И как только разница будет равна или больше (последнее в данном случае обязательно, так как возможна ситуация, когда программа проскочит точное значение 1000000). Проблемы могут возникать примерно раз в 50 суток, когда внутренний счетчик миллисекунд переполняется и снова начинает отсчет с нуля.

 

.c8r
.c8r аватар
Offline
Зарегистрирован: 15.11.2011

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

По этому я говорю про сторонние модули часов, но вероятность попадания в эти 50 суток крайне мала.

step962
Offline
Зарегистрирован: 23.05.2011

 А как вы представляете себе непрерывную работу автомобиля в течение 50 суток? Ведь топикстартер делает приблуду для автомобиля. А в автомобиле приблуды обычно питаются от бортовой сети, т.е. запускаются при старте двигателя.

karbid
Offline
Зарегистрирован: 27.11.2011

 Ну в данном случае ардуина будет подсоединена напрямую к цепи 30 ( постоянные 12 вольт).Ток потребления у нее мизерный
Собрал макет -с последней прошивкой там где блокируется кнопка при появлении питания на 11 вход не работает никак.
И еще вопрос- как можно остановить цикл delay? Я так понимаю, что команда break не поможет?

.c8r
.c8r аватар
Offline
Зарегистрирован: 15.11.2011

Обойти delay можно  по совету step962

 

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

.c8r
.c8r аватар
Offline
Зарегистрирован: 15.11.2011

Можно попробовать считывать сигнал с аналогового входа? 

karbid
Offline
Зарегистрирован: 27.11.2011

 а почему нет?

HOCKU
HOCKU аватар
Offline
Зарегистрирован: 25.04.2011

А вот так вот и будет выглядить программа с задержкой без delay

long startMillis = 0;   //время, когда нажата кнопка
long interval = 600000; //десять минут
int timer=0;            //включен "таймер" или нет

void setup(){
  pinMode(13,OUTPUT);
  attachInterrupt(1, timerStart, RISING);
}

void timerStart(){
  if(!timer) {
    timer=1;
    startMillis=millis();
    digitalWrite(13,1);
  }
}

void loop(){
  if(timer && (millis() - startMillis > interval)) {
    digitalWrite(13,0);
  }

  /* А тут вообще все что угодно может быть, и оно может выполняться без каких либо проблем, потому что никаких delay в программе нету. Более того, оно не будет влиять на работу "таймера".*/
}

Я как всегда код не проверял, но вроде все должно работать)

step962
Offline
Зарегистрирован: 23.05.2011

 Работать будет ровно один раз.

В блоке if (функция loop()) кроме гашения светодиода необходимо также делать сброс переменной timer, иначе в функции обработки прерывания (timerStart) запуск таймера будет заблокирован.

Если в программе имеется семафор (в нашем случае переменная timer), то он должен не только устанавливаться, но и сбрасываться.

HOCKU
HOCKU аватар
Offline
Зарегистрирован: 25.04.2011

блин, так и знал, что что-то забыл)

поправил.

 

long startMillis = 0;   //время, когда нажата кнопка
long interval = 600000; //десять минут
int timer=0;            //включен "таймер" или нет

void setup(){
  pinMode(13,OUTPUT);
  attachInterrupt(1, timerStart, RISING);
}

void timerStart(){
  if(!timer) {
    timer=1;
    startMillis=millis();
    digitalWrite(13,1);
  }
}

void loop(){
  if(timer && (millis() - startMillis > interval)) {
    digitalWrite(13,0);
    timer=0;
  }


}

 

karbid
Offline
Зарегистрирован: 27.11.2011

 Не работает с таким кодом

step962
Offline
Зарегистрирован: 23.05.2011

karbid пишет:

 Не работает с таким кодом

1) В чем выражается это "не работает"?

2) С каким именно "таким" кодом? Ваш скетч пока что невелик - приведите его полностью.

 

HOCKU
HOCKU аватар
Offline
Зарегистрирован: 25.04.2011

Код который я привел это всего лишь пример использования паузы без delay (и заодно применение внешних прерываний). И кстати, кнопка подключается к цифровому порту 3.

karbid
Offline
Зарегистрирован: 27.11.2011

 Ага, да, не обратил внимания что прерывание идет по 3-ей кнопке, извиняюсь:)
А можно теперь всё вместе собрать с с тем скетчем что в начале ? Что-то у меня с синтаксисом не то:)

karbid
Offline
Зарегистрирован: 27.11.2011
 long startMillis = 0; //время, когда нажата кнопка
long interval = 60000; //десять минут
int timer=0; //включен "таймер" или нет

void setup(){
pinMode(13,OUTPUT);
pinMode(4,OUTPUT);
pinMode(5,OUTPUT);
pinMode(6,OUTPUT);
pinMode(7,OUTPUT);
pinMode(8,OUTPUT);
pinMode(9,OUTPUT);
pinMode(10,OUTPUT);
pinMode(11,OUTPUT);
attachInterrupt(1, timerStart, RISING);
// инициализация порта
Serial.begin(9600);
}

void timerStart(){
if(!timer) {
timer=1;
startMillis=millis();
digitalWrite(13,1);
}
}

void loop(){
if(timer && (millis() - startMillis > interval)) {
digitalWrite(13,0);
timer=0;
}


{
byte a, b, c;
if (Serial.available() > 2) // ждем данные от плагина
{
a = Serial.read();
b = Serial.read();
c = Serial.read();
if(a == 0xFF) //если данные от плагина, то выполим команду
{
digitalWrite(b+1, (c==0x01) ? HIGH : LOW); //выполнить
} } }}
karbid
Offline
Зарегистрирован: 27.11.2011

 всем спасибо.все вработает:)

derrik
Offline
Зарегистрирован: 13.01.2012

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

whoim
Offline
Зарегистрирован: 03.11.2011

 derrik добавить переменную boolean flag, по нажатию менять ей значение на противоположное: = !flag

а в тексте программы исполнять код только если if (flag)

derrik
Offline
Зарегистрирован: 13.01.2012

 а как это практически выглядит? я тоже вроде как начинающий :)

derrik
Offline
Зарегистрирован: 13.01.2012
long startMillis = 0; //время, когда нажата кнопка
long interval = 60000; //десять минут
int timer=0; //включен "таймер" или нет
boolean flag;
void setup(){
pinMode(13,OUTPUT);
pinMode(4,OUTPUT);
pinMode(5,OUTPUT);
pinMode(6,OUTPUT);
pinMode(7,OUTPUT);
pinMode(8,OUTPUT);
pinMode(9,OUTPUT);
pinMode(10,OUTPUT);
pinMode(11,OUTPUT);
attachInterrupt(1, timerStart, RISING);
// инициализация порта
Serial.begin(9600);
}

void timerStart(){
if(!timer) {
timer=1;
startMillis=millis();
digitalWrite(13,1);
flag=!flag;
}
}

void loop(){
if(timer && (millis() - startMillis > interval)&&flag) {
digitalWrite(13,0);
timer=0;
}


{
byte a, b, c;
if (Serial.available() > 2) // ждем данные от плагина
{
a = Serial.read();
b = Serial.read();
c = Serial.read();
if(a == 0xFF) //если данные от плагина, то выполим команду
{
digitalWrite(b+1, (c==0x01) ? HIGH : LOW); //выполнить
} } }}

 

как-то так ?

whoim
Offline
Зарегистрирован: 03.11.2011

 мне кажется или timer и flag у вас за одним и тем же?)

derrik
Offline
Зарегистрирован: 13.01.2012

 если честно не понял вопроса:)

.c8r
.c8r аватар
Offline
Зарегистрирован: 15.11.2011

И в 25 строчке (flag==!flag;)  в точку вызова вернется просто логическое сравнение, не?

whoim
Offline
Зарегистрирован: 03.11.2011

 ну да, если надо инвертировать - одно равно (присвоение)

я тут с дельфи на ардуино пересел, в ужасе был, полчаса отвыкал от двоеточияравно))

а до этого в делфи отвыкал от сравнения ==

derrik
Offline
Зарегистрирован: 13.01.2012

 нет, не останавливат таймер повторное нажатие кнопки. может кто что-то еще посоветует?

whoim
Offline
Зарегистрирован: 03.11.2011

 И в 25 строчке (flag==!flag;)
зачем это?

derrik
Offline
Зарегистрирован: 13.01.2012

 исправил еще вчера

whoim
Offline
Зарегистрирован: 03.11.2011

 Повторю вопрос: зачем две переменные, флан и таймер?

Я правильно понимаю: задача исполнять код или не исполнять в зависимости от состояния, переключаемого кнопкой?

derrik
Offline
Зарегистрирован: 13.01.2012

 Немного не так- исполнять всегда код , но если кнопка нажата второй раз, то работа таймера прекращается

whoim
Offline
Зарегистрирован: 03.11.2011

 то есть примерно так:

1) есть переменная flag, инициализированная true;
2) при нажатии кнопки flag=!flag;
3) если flag то исполнять код

так?

whoim
Offline
Зарегистрирован: 03.11.2011

 3) если flag=true
        если пришло время

whoim
Offline
Зарегистрирован: 03.11.2011

 немного не понял, зачем вам прерывание?

whoim
Offline
Зарегистрирован: 03.11.2011

 перечитал тз. Ну, как то так:
переменная flas инициализированная false
если нажата кнопка flag=true и запоминаем время, включаем выход
если флаг=труе и время вышло, флаг в фальш и выключаем выход

м?

derrik
Offline
Зарегистрирован: 13.01.2012

 ну да, именно так