millis(); Как при нажатии на кнопку, его обнулить?!

JuriySOFT
Offline
Зарегистрирован: 18.04.2014

Всем доброго времени суток!

Подскажите пожалуйста как кнопкой обнулить функцию millis(); ?

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

JuriySOFT
Offline
Зарегистрирован: 18.04.2014

Вот небольшой набросок, подскажите где ошибка, никак не пойму:

#define ledPin 7 
#define knopka 3 
#define Rele1 2
unsigned long currentTime;
unsigned long loopTime;
void setup(){
  pinMode (Rele1,OUTPUT);
  pinMode(ledPin, OUTPUT);      
  currentTime = millis();     
  loopTime = currentTime;  
  pinMode(ledPin, OUTPUT);
  pinMode(knopka, INPUT_PULLUP);
}

 
void loop()
{
  currentTime = millis();                   
 if (digitalRead(knopka)==HIGH){
digitalWrite (Rele1,HIGH);}
if (currentTime >= (loopTime + 3000)){ 
       digitalWrite(ledPin, HIGH);     
    loopTime = currentTime;                         
  }
}

 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

JuriySOFT, вам нужно идти от простого к сложному. Вы вставляете строки из примеров не понимая как они работают. Естественно вы тут не добъётесь результата, пока не поймёте  бессмысленность строк 9,10, абсурдность строк 18,21,23.  В предыдущей вашей теме  я вам простое задание дал, на развитие логики.  Там как раз создаётся отсчёт времени после нажатия на кнопку. Шаг за шагом, и придёте к решению такой задачи как ваша первоначальная.

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

>Подскажите пожалуйста как кнопкой обнулить функцию millis(); ?

Никак.

Представте себе что у вас есть часы. Обыкновенные. Без таймера. И вам нужно сварять "яйцо-в-смятку". В рецепте вы вычитали, что "нужно закипятить воду, бросить яйцо, вынуть через три минуты". 
 Как вы обеспечите "варить яйцо три минуты", если переводить стрелки часов на 12:00 ночи вам религия не позволяет (ну или у часов отломанна головка и перевести их невозможно)? (это то что вы пытаетесь проделать спрашивая "как обнулить millis()?")

Каковы ваши "действия/рассуждения"?

 

Andrey_Y_Ostanovsky
Offline
Зарегистрирован: 03.12.2012

leshak пишет:

Никак.

Что значит "никак"? Я вот на кнопку "ресет" нажимаю - у меня millis() исправно обнуляется. :) Это какая-то неправильная кнопка?

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

Andrey_Y_Ostanovsky пишет:

leshak пишет:

Никак.

Что значит "никак"? Я вот на кнопку "ресет" нажимаю - у меня millis() исправно обнуляется. :) Это какая-то неправильная кнопка?

Да. Неправильная. Почитайте условия задачи. "ничается отсчет при включении" - не подходит.

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

Ну или я чего-то не понимаю. И скажем вы знаете как, при помощи ресет, скажем включить светик через три минуты после нажатия кнопки, потом подождать 4-ре минут, а потом выключить. И все это без delay(). 

Andrey_Y_Ostanovsky
Offline
Зарегистрирован: 03.12.2012

leshak пишет:

И скажем вы знаете как, при помощи ресет, скажем включить светик через три минуты после нажатия кнопки, потом подождать 4-ре минут, а потом выключить. И все это без delay().

Ну-у, я даже не знаю... :) Записать в eeprom, нажать на ресет из скетча, прочитать из eeprom - что делать после ресета. Без delay(), как и просили...

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

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

Andrey_Y_Ostanovsky пишет:

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

Корректно. Reset-том, вы дуину перегружаете. А не делается действие "обнуление millis())". Мы же не в анекдоте где головную боль лечат отрубанием головы. Так что не нужно высказываний вида "заявлять что топор не является средством от головной боли - не совсем корректно". Я считаю, что, все-таки, не является :) Лучше цитрамон или что-то подобное.

Geronimo
Offline
Зарегистрирован: 06.05.2013

а откуда эта функция беред значения? может можно обнулить соответсвующий регистр?

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

Ну если очень любопытно, то можете посмотреть в файлик hardware\arduino\cores\arduino\wiring.c

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

И главное "зачем?" Прости, но это, в любом случае "удаление гланд, через Ж.., автогеном".

Если вы считате что "так проще". То тогда вопрос про "яйцо и часы" - можете отнести к себе тоже.  Вы будете стрелки часов переводить? Или все-таки попроще сможете отсчитать 3 минуты без попыток вскрыть ломом бабушкины ходики?

Geronimo
Offline
Зарегистрирован: 06.05.2013

то что это полное извращение это понятно)

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

leshak, Geronimo, в принципе можно и обнулять millis, я лично особого извращения тут не вижу... Только не саму миллис(), а её первопричинную переменную.  Вызываем в нужном месте скетча timer0_millis=0 , и дело в шляпе. Только нужно сделать #include <wiring.c> что -б был доступ к закрытым переменным.

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

> Вызываем в нужном месте скетча timer0_millis=0

Может вы и правы. Вот только я не уверен. Что дело "будет в шляпе". Вернее "может и заработает", но вот когда и в каком месте вылезут "неприятные эффекты" - я не уверен. Ну как минимум, а если в этот момент сработает timer0? Поняно что сейчас вы вспомните про "запрет прерываний", но... ведь сразу не вспомнили. И еще могут быть "нюансы". А сколько еще библиотек, могут расчитывать на то что millis() растет линейно, и ее "резкое падение" означаент "было переполнение"? И еще могут быть... вообщем "нафиг, нафиг...". В лоб, может выйти больно. Причем не сразу, а "когда пару дней лбом об стол в дебаге побъешься". 

А еще есть micros(), про который вы забыли... и они с millis() получаются "разойдутся". А еще, там, в зависимости от того под какой камень компилим... чуть чуть отличается логика и какие переменные используются. Вот здрово будет потом разбиратся почему "на этой плате работает, а на этой - не работает"....

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

Я думаю вы поняли, что лично меня убедить в целесообразности/безопасности обнуления millis().

Ну или с другого конца. timer0_millis объявленна где-то в .h файлах? Нет. То есть это какая-то ПРИВАТНАЯ переменная. Внутреняя реализация. Которая может поменять в любой момент. Как угодно. Исчезнуть при любом обновлении ArduinoIDE или, что еще хуже, начать использоваться, внутри, как-то совсем по другому. Нарушение инкапсуляции - один из смертных грехов :)

Кстати, компилятор, уверен на 99% скажет вам тоже самое. И на попытку не то что поменять, а даже "прочитать" timer0_millis - пошлет вас нафиг. Не, при желании, через указатели мы до нее можем добратся. Но это уже будет 100% порнография.

Или начинать резть руками в Arduino.h. Что уже по определнию является "грязнохаком".

Вы по прежнему не видите в этом извращения? ;)

 

com
Offline
Зарегистрирован: 06.09.2013

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

не, должно быть в нашей жизни хоть что-то незыблемое, и пусть этой основой и будет millis :)

JuriySOFT
Offline
Зарегистрирован: 18.04.2014

Ой! Как много "страшных" сообщений было написано за это время!....

Быть может можно сделать как-то попроще?

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

если(millis()-currentMillis()+10000>=10000) то .......}

где currentMillis = millis()

 

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

Я ж только начал изучать АРдуину....

П.С. Может есть где учебники именно где можно подробно прочитать про millis() и все что с этим связано?

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

JuriySOFT
Offline
Зарегистрирован: 18.04.2014

Я тут немного поэксперементировал и вот что получилось:



#define ledPin 7 
#define knopka 3 
#define Rele1 2
unsigned long currentTime;
void setup(){
  pinMode (Rele1,OUTPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(knopka, INPUT); 
}

 
void loop()
{
 if (digitalRead(knopka)==HIGH){
  currentTime = millis(); 
bool  change = millis()-currentTime;
   if (currentTime-change>=2000){ 
    digitalWrite(ledPin, HIGH);  
  }
digitalWrite (Rele1,HIGH);}
}

 

 

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

Geronimo
Offline
Зарегистрирован: 06.05.2013

У ткбя переменная change всегда равна 0

JuriySOFT
Offline
Зарегистрирован: 18.04.2014

Geronimo пишет:
У ткбя переменная change всегда равна 0

А как же тогда объяснить то, что отсчет 2х секунд все равно есть, но работает не так как мне надо?

Клапауций
Offline
Зарегистрирован: 10.02.2013

JuriySOFT пишет:

А как же тогда объяснить то, что отсчет 2х секунд все равно есть, но работает не так как мне надо?

однозначно - чюдо.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

leshak, чессгря я не отношусь к внутренним функциям ардуины как к чему-то священному, что нельзя трогать. Трогаю, и трогал раньше, ибо интересно :) Ну да, при какой-нибудь ситуации теоритически могут быть проблемы, но с другой стороны я и не предлагаю эту фишку использоваться всем подряд. Это из разряда, "как нет кнопки обнуления, а ресет?" :-))) Как в таких случаях говорят  "используете на свой страх и риск"

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

JuriySOFT, вы заблуждаетесь, думая что у вас только с millis проблема. У вас проблема во всём, вы берёте что-то из примеров, и непонимая как это работает вставляете в свой скетч. Изучите справочник языка ардуино http://arduino.ru/Reference

JuriySOFT
Offline
Зарегистрирован: 18.04.2014

dimax пишет:

JuriySOFT, вы заблуждаетесь, думая что у вас только с millis проблема. У вас проблема во всём, вы берёте что-то из примеров, и непонимая как это работает вставляете в свой скетч. Изучите справочник языка ардуино http://arduino.ru/Reference

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

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

JuriySOFT,  да, там не всегда понятно, не спорю. Но тем не менее у вас не должно быть в скетче ни одной строчки, смысл которой вам не ясен как дважды два. Если вы присвоили переменной CHANGE тип bool значит вы не понимате что такое bool. Тут написано более чем понятно  http://arduino.ru/Reference/BooleanVariables

Geronimo
Offline
Зарегистрирован: 06.05.2013

Разве bool определен не как тайпдеф к чару? Синтаксически верно, но, но семантически ерунда написана.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Geronimo, долго думал над вашей фразой, но ничего не понял :)  Что  общего между bool и char ? В теории bool может достигать 255, но на практике всё что не 0 -то 1.

Geronimo
Offline
Зарегистрирован: 06.05.2013

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

Kolaha
Offline
Зарегистрирован: 29.12.2016

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

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

int Led=13; // светодиод(реле)
int Butt=12;//кнопка
unsigned long Timer;
unsigned long Waiting=10000;//величина выдержки

void setup(){
  pinMode(Led,OUTPUT);    
  pinMode(Butt,INPUT);
  digitalWrite(Butt,1);    
  }
 
void loop(){
  if (digitalRead(Butt)==0 && Timer==0) {//если таймер не взведен и кнопка нажата
  Timer=millis()+Waiting;// то взводим таймер 
  digitalWrite(Led,1);//и активируем диод
  }
  if (Timer<=millis() && Timer!=0) {//если таймер был взведен и текущее время его превысило
    digitalWrite(Led,0);// то тушим свет
    Timer=0;// и сбрасываем таймер (в ущелье, на самое дно)
  }
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

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

Kolaha
Offline
Зарегистрирован: 29.12.2016

qwone пишет:

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

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

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

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

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

/* определяет короткое нажатие и длительное нажатие
после определеного времени
#1
кнопка1 -> 2 (btn1_pin) 0 нажата /1 нет
*/
// #1
const int btn1_pin = 2; // вывод кнопки
bool btn1, btn1_old; // значение на кнопке без дребезга, тоже но стар значение
bool bounce_btn1 = 0; // антидребезговый флаг
uint32_t time_btn1  ; // длительность нажатия
const uint32_t const_time_btn1 = 500  ; // константа длительности нажатия ниже короткое нажатие выше длиное,миллисек
void setup() {
  Serial.begin(9600);
  // #1
  pinMode(btn1_pin, INPUT_PULLUP); // подключить кнопку 1 с подтяжкой
  btn1 = digitalRead(btn1_pin);

}

void loop() {
  // #1
  static uint32_t past_1 = 0 ;
  static uint32_t past1_1 = 0 ;
  if (! bounce_btn1 && btn1 != digitalRead(btn1_pin)) { // если прошел фронт изм на выводн
    bounce_btn1 = 1;                                 // выставить флаг
    past_1 = millis();                          // сделать временую засветку
  }
  else if ( bounce_btn1 && millis() - past_1 >= 40 ) { // если прошло антидребезговое время
    bounce_btn1 = 0;      // то снять флаг
    btn1_old = btn1;
    btn1 = digitalRead(btn1_pin) ; // прочитать реальное значение на выводе
    if (btn1_old && ! btn1) {      // если обнаружилось что это было нажатие
      past1_1 = millis();
      Serial.println("Press down");
    }
    if (! btn1_old && btn1) {      // если обнаружилось что это было отжатие
      time_btn1 = millis() - past1_1;

      Serial.print(time_btn1);
      if (time_btn1 < const_time_btn1)
        Serial.println("  Press short up");
      else Serial.println("  Press long up");
    }
  }
}

 

Kolaha
Offline
Зарегистрирован: 29.12.2016

а если так?

int Led=13;
int Butt=12;
unsigned int proof=0;
unsigned long Timer=0;
unsigned long Waiting=10000;

void setup(){
  pinMode(Led,OUTPUT);    
  pinMode(Butt,INPUT_PULLUP);    
  }
 
void loop(){
  if (!digitalRead(Butt)) proof=proof+2;
  if (digitalRead(Butt)) if (proof) proof--; 
  if (proof>10000 && !Timer) {
    Timer=millis()+Waiting;
    digitalWrite(Led,1);
    proof=0;
  }
  if (Timer<=millis() && Timer) {
    digitalWrite(Led,0);
    Timer=0;
  }
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

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

1

int Led=13;
int Butt=12;
// никогда не пишите так.
const int Led_pin=13;// пин светодиода
const int Butt_pin=12;// пин кнопки
// а так и только так
// const int  говорит компилятору, что это константа и не надо на это выделять память
// Led_pin,Butt_pin говорит программисту , что это вывод ноги МК и ничего с ним делать не надо
// А вот состояния выводов будут Led,Butt. Потому что иначе надо называть так Led_val,Butt_val
// что просто удлиняет название переменных, которые будут часто встречатся в программе.

 

Kolaha
Offline
Зарегистрирован: 29.12.2016

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

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Kolaha пишет:

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

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

Разумеется таймер millis() остановить нельзя, но можно запомнить начало в переменной и указать в константе интервал времени от этого начала. Но так как надо сделать это один раз, то нужен флаг. Что у вас написано. Но опять же , в такой конструкции можно ошибиться. Так что бы ошибок было поменьше и нужен стиль.  Вот от сюда источник придирок к написанию кода.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

qwone пишет:

Разумеется таймер millis() остановить нельзя,

Если сильно хочется, то можно  и останавливать и обнулять:-)  обнулить совсем просто -в шапке подцепить #include "wiring.c" и потом обнулить timer0_millis=0;

satelit 2
Offline
Зарегистрирован: 04.12.2016

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

в моем пректе два дня без тормозов сработает?

satelit 2
Offline
Зарегистрирован: 04.12.2016

satelit 2 пишет:

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

в моем пректе два дня без тормозов сработает?

у меня уже нервов не хватает, да я сегодня под шафэ.  перепишу .

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

satelit 2
Offline
Зарегистрирован: 04.12.2016

у меня планов собралось, а вопросов больше, а в програмировании ноль, но хотелка решается уже 

satelit 2
Offline
Зарегистрирован: 04.12.2016

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

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

satelit 2 пишет:

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

 

http://arduino.ru/Reference

satelit 2
Offline
Зарегистрирован: 04.12.2016

vvadim пишет:

satelit 2 пишет:

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

 

http://arduino.ru/Reference

я изучил

Kolaha
Offline
Зарегистрирован: 29.12.2016

millis() - это системная переменная, не имеющаяя отношения к Вашей программе и её исполнению. Следовательно, она Вам ничего не "тормозит".

satelit 2
Offline
Зарегистрирован: 04.12.2016

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

Tenshi26
Offline
Зарегистрирован: 31.01.2017

А такой вариант- если нажата кнопка то

int tochkaOtcheta=0
// если нажата кнопка то
tochkaOtcheta = millis();

ONfaer[i] = millis()-tochkaOtcheta; // запись в масив таймера 

И будут писаться значения нажатия кнопки за ноль

Клапауций 823
Клапауций 823 аватар
Offline
Зарегистрирован: 13.01.2017

Tenshi26 пишет:

А такой вариант- если нажата кнопка то

int tochkaOtcheta=0
// если нажата кнопка то
tochkaOtcheta = millis();

ONfaer[i] = millis()-tochkaOtcheta; // запись в масив таймера 

И будут писаться значения нажатия кнопки за ноль

i чему равно?

Tenshi26
Offline
Зарегистрирован: 31.01.2017

В оглавлении я создал масив ONfaer[50]- Это 50 ячеек

А тепер пишу ONfaer[i] = millis()-tochkaOtcheta; i++;

что означает что каждая запись будет в новой ячейке

если же нужна определенная то i=5 например

Tenshi26
Offline
Зарегистрирован: 31.01.2017

И сделано это для того чтобы после нажатия в этой переменной таймер будет отсчитываться с нуля так как например прошло с включения ардуины 5 минут 5-5 =о а вот следующая минута 6-5=1))) это мненадо для создания трека действий после нажатия кнопки

Клапауций 823
Клапауций 823 аватар
Offline
Зарегистрирован: 13.01.2017

ок.

Tenshi26
Offline
Зарегистрирован: 31.01.2017

http://arduino.ru/Reference/Array

Это масив количество ячеек памяти тоесть 50 переменных я могу записать под этим названием изменяя тока цифру

Чтобы не писать каждый раз новую переменную

Kolaha
Offline
Зарегистрирован: 29.12.2016

Можно пойти дальше и сделать под каждую переменную отдельную ардуино, со своим отдельным рейд массивом дисков на ССД.

Клапауций 823
Клапауций 823 аватар
Offline
Зарегистрирован: 13.01.2017

Kolaha пишет:

Можно пойти дальше и сделать под каждую переменную отдельную ардуино, со своим отдельным рейд массивом дисков на ССД.

один рейд - одна переменная

и, писать летопись вселенной втуда