как Включить на некоторое время?

compot
Offline
Зарегистрирован: 19.06.2012

Здравствуйте уважаемые форумчане!

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

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

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

В общем как то так - здесь независимо управляется двумя выводами:

#define NASOS_PIN 13 // Вывод к котрому подключена нагрузка
#define TIME_ON_NASOS 10000  // Время в течении, которого на выводе 1
#define TIME_OFF_NASOS 180000 // Время в течении, которого на выводе 0
boolean state_nasos = 0; // Переменная для хранения состояния вывода
unsigned long new_millis_nasos = millis(); // Переменная для хранения времени

#define SVET_PIN 10 // Вывод к котрому подключена нагрузка
#define TIME_ON_SVET 1000 // Время в течении, которого на выводе 1
#define TIME_OFF_SVET 3000 // Время в течении, которого на выводе 0
boolean state_svet = 0; // Переменная для хранения состояния вывода
unsigned long new_millis_svet = millis(); // Переменная для хранения времени

void setup() {
  pinMode(NASOS_PIN, OUTPUT); // Настраиваем вывод на выход     
  pinMode(SVET_PIN, OUTPUT);  // Настраиваем вывод на выход  
}

void loop(){ 
// Управление насосом:
  if(millis() > new_millis_nasos){
    state_nasos = !state_nasos;
    digitalWrite(NASOS_PIN, state_nasos);
    if(state_nasos){
      new_millis_nasos = millis() + TIME_ON_NASOS;
    }
    else{
      new_millis_nasos = millis() + TIME_OFF_NASOS;
    }
  }
  
// Управление светом:
  if(millis() > new_millis_svet){
    state_svet = !state_svet;
    digitalWrite(SVET_PIN, state_svet);
    if(state_svet){
      new_millis_svet = millis() + TIME_ON_SVET;
    }
    else{
      new_millis_svet = millis() + TIME_OFF_SVET;
    }
  }
  
}


проверить не пока не начем. По аналогии делаете сколько нужно таких таймеров.

compot
Offline
Зарегистрирован: 19.06.2012

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

compot
Offline
Зарегистрирован: 19.06.2012

Выдает ошибку в 4ой строке

error: expected unqualified-id before numeric constant

 

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

 А еще в разделе программирование есть пример 

"Мигаем светодиодом без delay"

compot
Offline
Зарегистрирован: 19.06.2012

leshak пишет:

 А еще в разделе программирование есть пример 

"Мигаем светодиодом без delay"

читал я его... но я же писал что там он скоко горит стоко и негорит... малех разное...

ourlive
Offline
Зарегистрирован: 26.05.2012

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

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

compot
Offline
Зарегистрирован: 19.06.2012

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

 

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

Версия IDE какая? 

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

Вы что нибудь в коде меняете? 

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

 Попробовал - у меня сей скетч компилируется без проблемм.

Это еще может из-за бажных библиотек быть. Попробуйте, у вас пустой скетч. с пустыми setup и loop компилируется?

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

 А..... я догадался :)

Вы как скетс с форума копируете? Выделили и скопировали?

Тогда еще номера строк захватываются. И их нужно руками удалять.

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

compot
Offline
Зарегистрирован: 19.06.2012

спасибо! вот оно реальное решение вопроса))) меня еще удивило, сначало ошибка в 4ой строке, потом в 3ей.... теперь всё верно... спасибо большое всем, по коду мне впринципе все понятно... я код понимаю токо писать сам еще неособо могу, токо начинаю... нюансов много.

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

 Ну тогда, на всяк случай, прочитайте еще как правильно вставлять код, вдруг понадобится :)

http://arduino.ru/forum/obshchii/vstavka-programmnogo-koda-v-temukomment...

Dima85
Offline
Зарегистрирован: 07.01.2013

Обясните пожалуйста подробней этот кусок кода:

31 // Управление светом:
32 if(millis() > new_millis_svet){
33 state_svet = !state_svet;
34 digitalWrite(SVET_PIN, state_svet);
35 if(state_svet){
36 new_millis_svet = millis() + TIME_ON_SVET;
37 }
38 else{
39 new_millis_svet = millis() + TIME_OFF_SVET;
40 }

Меня беспокоит 32 строчка - millis(), такое ощющение что это сработает только 1 раз, т.к. millis() нигде не обнуляется и пойдет дальше. Или я ошибаюсь? + millis() насколько я понимаю умеет хранить значение от 0 до 4294967295. Это около 50 дней. После обнуления этот код нормально себя будит вести?

Задача включать 1 свето диод каждые 2 дня на 30 секунд. И второй каждые 3 дня на 40 секунд.

maksim
Offline
Зарегистрирован: 12.02.2012
//  функция millis() возвращает текущее значеие счетчика, который запущен с начала старта МК
// переменная state_svet хранит состояние света 1 или 0 - вкл. или выкл.
// переменная new_millis_svet хранит сумму заданного времени и значение счетчика на момент присваивания
// TIME_ON_SVET и TIME_OFF_SVET - заданное время, время которое будет включен или выключен свет

// Управление светом:
if(millis() > new_millis_svet){ // если текущее значение счетчика превысило значение хранящееся в new_millis_svet, то
  state_svet = !state_svet;     // меняем состояние state_svet на противоположное, если был 0, то меняем на 1 и наоборот.
  digitalWrite(SVET_PIN, state_svet);  // устанавливаем вывод в соответствующее состояние
  if(state_svet){  // если state_svet равен 1 (больше нуля, истина,..), то
    new_millis_svet = millis() + TIME_ON_SVET;  // присваиваем переменной new_millis_svet сумму текущего состояния счетчика и заданного времени
  }
  else{  // инече
    new_millis_svet = millis() + TIME_OFF_SVET;  // присваиваем переменной new_millis_svet сумму текущего состояния счетчика и другого заданного времени
  }
}

 

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

Dima85 пишет:
Меня беспокоит 32 строчка - millis(), такое ощющение что это сработает только 1 раз, т.к. millis() нигде не обнуляется и пойдет дальше. Или я ошибаюсь? + millis() насколько я понимаю умеет хранить значение от 0 до 4294967295. Это около 50 дней. После обнуления этот код нормально себя будит вести?

Задача включать 1 свето диод каждые 2 дня на 30 секунд. И второй каждые 3 дня на 40 секунд.

millis() нельзя обнулить ("обычными средствами"), прочитайте внимательно описание этой функции, эта функция только возвращает текущее значение счетчика с запуска МК.
В вашем случае лучше использовать таймер реального времени - RTC, например, DS1307.

Dima85
Offline
Зарегистрирован: 07.01.2013

Тоесть насколько я понимаю в вашем примере new_millis_svet с каждым включением\выключением увеличивается, так?

В таком случае может случится такое? - Допустим new_millis_svet после долгово времени у нас стал 4294967200 в какое-то время millis() становится больше, включается свет и в new_millis_svet присваивается еще + 180000 получается уже 4295147290. 

Но в millis() ведь есть придел на хранение данных и допустим при 4294967295 он обнулился и начал считать с нуля. Заметьте new_millis_svet у нас стало больше чем максимальное число в millis() таким образом больше не включится свет. Так получается?

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

Если вы не заметили, то new_millis_svet тоже имеет тип unsigned long, который так же может принимать значения от 0 до 4294967295, поэтому стать больше эта переменная не может, а при переполнении тот остаток, который "не влезет" в переменную будет записан в нее после ее обнуления, так что все будет в порядке.

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

Не совсем так.

Рассмотрим проблему на примере байта (0...255). При счете от 0 с шагом 10 (TIME_OFF_SVET/TIME_ON_SVET=10) вплоть до 250 все будет в порядке. Но затем:

new_millis_svet = millis() + TIME_OFF_SVET => 250+10 => 300 -> 4

И с этого момента условие

if(millis() > new_millis_svet)

будет исполняться при каждом прохождении цикла до тех пор, пока счетчик millis не достигнет значения 255 (мы ведь и его до byte укоротили), не произойдет переполнение и он не обнулится. После этого сумасшествие закончится. Вплоть до нового подхода к опасной границе.

Крах идеи? Вовсе нет. Просто условие следует переписать:

if(millis() - old_millis_svet > TIME_OFF_SVET)

И тогда для случая, когда old_millis_svet=250, а millis()<=255 (пусть будет 254), имеем:

254-250=4 < 10 - все нормально

После того, как счетчик перевалит через 255 и снова начнет считать с 0:

0-250=-250 => 6 < 10 - все нормально

Ну и далее - вплоть до millis()=5:

5-250=-245 => 11 > 10 - условие выполнилось, переходим к миганию диодами.

 

PS: old_millis_svet, как вы понимаете - момент последнего мигания. В противоположность моменту следующего мигания (переменной new_millis_svet).

Dima85
Offline
Зарегистрирован: 07.01.2013

Спасибо. Разобрался.

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

Ну да, раз в 50 дней жди прикола ))) на несколько минут.

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

 

maksim пишет:

Ну да, раз в 50 дней жди прикола ))) на несколько минут.

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

Кстати сам долгое время именно "вычислял", как-то оно "интуитивней/человечней" (и не понимал зачем в туториалах через разницу делают). Потом как-то наткнулся на переполнение, вначале написал через if-фы сравнивал кто больше, кто меньше и разную логику вычисления делал... заработало. Начал сокращать и пришел к тому что в обоих случаях код одинаковый. Не понял "как это".... начал думать, как раз используя прием step962 взяв для примера 0...255. И дошло. При переполнении у нас разница выходит отрицательная, происходит "переполнение в обратную сторону" и .... все хорошо. millis()-eventTime всегда дает правильный интервал если пользоватся беззнаковыми типами.

Правда если во время "Ожидания" дважды уложится 49 дней.... вот тут уже нужно будет что-нибудь хитрить.

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

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

Dima85
Offline
Зарегистрирован: 07.01.2013

maksim пишет:

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

compot, создавший эту тему, наверняка рассчитывает держать включенным arduino постоянно. :)

 И я бы был осторожней с выражениями о том что мало у кого arduino работает более 50 дней. В моем городе есть маленькая фирмачка, которая занимается так называемыми "Умными домами". К моему удивлению они в большинстве проектов сейчас используют именно arduino - который следит за температурой в доме, светом. Как вы понимаете он должен быть включен постоянно.

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

>>Как вы понимаете он должен быть включен постоянно.<<

Не обязательно. МК вполне можно сбрасывать , скажем раз в сутки. Чтоб не обнулились значения нужных переменных можно писать их в ипром перед сбросом.

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

Я просто включил релюшку в разрыв питания МК , включение релюшки с ноги МК. МК дергал эту релюшку раз в пять суток. Вот так и работает до сих пор. Уже около года без фактического отключения всей вывески.

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

Dima85 пишет:

compot, создавший эту тему, наверняка рассчитывает держать включенным arduino постоянно. :)

Ну я за него рад ) как говорится "дареному коню...", надо будет сам исправит.

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

nestandart пишет:

>>Как вы понимаете он должен быть включен постоянно.<<

Не обязательно. МК вполне можно сбрасывать , скажем раз в сутки. Чтоб не обнулились значения нужных переменных можно писать их в ипром перед сбросом.

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

Я просто включил релюшку в разрыв питания МК , включение релюшки с ноги МК. МК дергал эту релюшку раз в пять суток. Вот так и работает до сих пор. Уже около года без фактического отключения всей вывески.

Так можно было просто дергать ресет соседней ногой.

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

>>Так можно было просто дергать ресет соседней ногой.<<

Не получится. При запуске МК дергает всеми ногами. Он просто войдет в состояние бесконечного резета. А на релюшке нехилый кондер стоял. Короткого импульса не хватало а вот удержания напруги в течении нескольких секунд вполне.

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

Да ну ладно вам, вы сами это проверяли? Все нормально, бут дергает только 13 вывод (у меня Duemilanove).

Проверьте, вот вам блинк с ресетом, 12 ногу на ресет.

void setup() {                
  delay(1000);
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);   // set the LED on
  
  digitalWrite(12, HIGH); 
  pinMode(12, OUTPUT);
 
}

void loop() { 
  delay(1000);    
  digitalWrite(12, LOW);    // set the LED off
}

 

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

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

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

nestandart пишет:

>>Так можно было просто дергать ресет соседней ногой.<<

Не получится. При запуске МК дергает всеми ногами. Он просто войдет в состояние бесконечного резета. А на релюшке нехилый кондер стоял. Короткого импульса не хватало а вот удержания напруги в течении нескольких секунд вполне.

А ресет дергать через RC цепочку?

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

Мне кажется вы живая иллюстрация к статье  Легкий способ бросить писать идеальный код

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

>>Вместо поменять логику - добавлять деталь.<<

В смысле.  Я резетил МК не для каких то конкретных целей а просто для профилактики. Т.к. я не знаю как поведет себя прогрмма через год. Так вот и пусть себе резетится раз в пять суток.

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

maksim, действительно! Я почему то свято верил в то чтоМК дергает всеми ногами.

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

Где то была такая тема, что у кого то МК при запуске дергает всеми ногами, и кстати, а может и дергает, но логическая 1 не сбросит МК, а наоборот.

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

nestandart пишет:

>>Вместо поменять логику - добавлять деталь.<<

В смысле.  Я резетил МК не для каких то конкретных целей а просто для профилактики. Т.к. я не знаю как поведет себя прогрмма через год. Так вот и пусть себе резетится раз в пять суток.

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

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

В данном случае я бы скорее использовал watchdog.

Не думаю что какой-то из этих подходов является "истинно верным" (програмно/аппаратно), всегда должен быть "баланс". Но все мы люди. Поэтому "перекос" - всегда неизбежен. Просто перекос в "чужую сторону" - вызывает умиление, а в свою - гордость (в запущенном случае ;) или просто не заметен.

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

leshak пишет:

 Давно заметил что кто пришел из "радио-кружков" что можно предпочитают решить "аппаратно"

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

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

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

YuraSh
Offline
Зарегистрирован: 18.01.2013

Подскажите новичку. У меня похожая задача как у топикстартера. Но включаться должно на 0,2с до 1 с. Выключаться соответсвенно на 0,8с до 0с.

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

Вопрос. Хватить ли времени (около 0,2с) для выполнения основной части программы (считывание около10-15 датчиков, управление около 10-15 нагрузок по простым алгоритмам, вывод информации на экран)?

Не проходите мимо!

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

YuraSh пишет:

Вопрос. Хватить ли времени (около 0,2с) для выполнения основной части программы (считывание около10-15 датчиков, управление около 10-15 нагрузок по простым алгоритмам, вывод информации на экран)?

А как на этот вопрос может ответить кто-то кроме вас? Сделайте serial.println("Before:");println(millis()); до основной части и serial.println("After:");println(millis()); после.

Ну и узнаете сколько он у вас выполняется.

Если "слишком долго" - будете думать как улучшить. всякие delay(), pulseIn(), stepper(), while(ЧТО_НИБУДЬ_ЖДЕМ){} будете выкидывать.

 

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

>>Не проходите мимо<<

Cоздайте новую тему и распишите алгоритм по пунктам.

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

Помогите программно реализовать следующий алгоритм:

DC двигатель вращается в одном направлении в течении X минут,

останавливается и стоит Y мин,

DC двигатель вращается в ОБРАТНОМ направлении теже X мин,

останавливается и стоит теже Y минут.

Двигатель подключен  с помощью шилда на L298n  микросхеме.

#define TIME_ON_NASOS 2000  // Время в течении, которого на выводе 1
#define TIME_OFF_NASOS 5000 // Время в течении, которого на выводе 0
boolean state_nasos = 0; // Переменная для хранения состояния вывода
unsigned long new_millis_nasos = millis(); // Переменная для хранения времени

#define TIME_ON_SVET 2000 // Время в течении, которого на выводе 1
#define TIME_OFF_SVET 5000 // Время в течении, которого на выводе 0
//boolean state_svet = 0; // Переменная для хранения состояния вывода
unsigned long new_millis_svet = millis(); // Переменная для хранения времени

#define D2 4          // Направление вращение двигателя 2
#define M2 5          // ШИМ вывод для управления двигателем 2

//bool direction = 0;   // Текущее направление вращения 
boolean direction;
//boolean direction = 0;//Возможно так правильнее
int value;            // Текущее значение ШИМ

void setup() 
{ 
  Serial.begin(9600);
  //pinMode(D1, OUTPUT);
  pinMode(D2, OUTPUT);  
} 

void loop() 
{ 
 // Управление насосом:
  if(millis() > new_millis_nasos){
    state_nasos = !state_nasos;
    //forward_plus();
    Serial.println("forward");
    forward();
    if(state_nasos){
     new_millis_nasos = millis() + TIME_ON_NASOS;
     //Serial.print(millis() + TIME_ON_NASOS);
    }
    else{
      Serial.println("motor_stop");
      motor_stop();
      new_millis_nasos = millis() + TIME_OFF_NASOS;
   }
  }
 
 // Управление насосом:
  if(millis() > new_millis_svet){
    state_nasos = !state_nasos;
    Serial.println("back");
    back();
    if(state_nasos){
      new_millis_svet = millis() + TIME_ON_NASOS;
    }
    else{
      Serial.println("motor_stop");
      motor_stop();
      new_millis_svet = millis() + TIME_ON_NASOS;
    }
  }
 //Serial.println("Worck"); 
}
 void motor_stop()
 {
   value=0;
  digitalWrite(D2, direction);
    //analogWrite(M1, value);       // Задаем скорость вращения
    analogWrite(M2, value);
   // Serial.println(value);
     
 }
void forward()
{
  value=255;
direction=0;
 //digitalWrite(D1, direction);  // Задаем направление вращения
    digitalWrite(D2, direction);
    //analogWrite(M1, value);       // Задаем скорость вращения
    analogWrite(M2, value);
   Serial.println(value);
    //delay(20); 
}
void back()
{
  value=255;
  direction=1;
  //digitalWrite(D1, direction);  // Задаем направление вращения
     digitalWrite(D2, direction);
    //analogWrite(M1, value);       // Задаем скорость вращения
    analogWrite(M2, value);
    //Serial.println(value);
    //Serial.println("HHHHHHH");
   // delay(20); 
}

 

xkp
Offline
Зарегистрирован: 17.01.2015

можно поподробнее про пример step962 ?

Максимальное значение millis 4294967295, если мне надо задержку (время включения) в 1 секунду то мне надо записать TIME_ON_SVET = 1000;, а в old_millis_svet значение (4294967295-new_millis_svet), а new_millis_svet = millis() + TIME_ON_SVET

итого получаем последнюю строчку

old_millis_svet = 4294967295 - millis() + TIME_ON_SVET;

или я что то напутал?