2 Реле времени. Задержка включения и выключения.

deliter
Offline
Зарегистрирован: 18.06.2014

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

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

Реле времени 1! Нужно чтобы при нажатии кнопки и ее удержании через 5, предположим, секунд загорался светодиод и горел до отпускания кнопки.

Реле времени 2! Если кнопка нажата - светодиод горит. Как только кнопка отпущена - засекаем 10 секунд и выключаем светодиод.

Я все сделал с использованием delay(), и интервалом в 10мс. В целом это ОК, так как итераций много и успевает вылавливать оба "включения - выключения", но почитав мануалы решил переделать на mills.. вот тут  прошу помощи.


//реле включения с задержкой и выключения с задержкой
//версия 0.7

const int buttonPin1 = 8;//Контакт "генератор"
const int buttonPin2 = 9;//Контакт "зажгание"
// Это кнопки для Ардуины
const int ledPin1 = 13; //Реле 1 - управление
const int ledPin2 = 12; //Реле 2 - управление

int offtimer =500; //Таймер выключения = 500 = 5 секунд.
int ontimer = 0; // Таймер включения

// переменные положения кнопок
int buttonState1 = 0;         //генератор
int buttonState2 = 0;        //зажигание

void setup() {
  pinMode(ledPin1, OUTPUT); //этот пин выход
  pinMode(ledPin2, OUTPUT); //этот пин выход  
  pinMode(buttonPin1, INPUT);//этот пин вход
  pinMode(buttonPin2, INPUT); //этот пин вход
  
}

void loop()

{
  // читаем состояние пинов
  buttonState1 = digitalRead(buttonPin1);
  buttonState2 = digitalRead(buttonPin2);
  
  if (buttonState1 == HIGH) //если есть напряжение
    {     
    // подаем сигнал на реле 1
    digitalWrite(ledPin1, HIGH);  
    offtimer = 500;  //кончился таймер - перезаполняем его
    } //if1
  else { //если питания пропало
    if (offtimer == 0) //если таймер еще не оработал (полный)
    {
      digitalWrite(ledPin1, LOW); //выключаем реле 1
    }//if2
   else { // Если не полный таймер
     offtimer = offtimer -1; //уменьшаем на 1 (1/10 секунды)
     delay (10); //ожидаие чтобы работал таймер
   }//else2 
 //  
  }//else1
  
  if (buttonState2 == HIGH) //если есть питание зажигания
  {
 
     if (ontimer == 300) //если уже прошло 3 секунды
     {
        digitalWrite(ledPin2, HIGH); //включаем реле 2
        
     }
     else //если не прошло
     {
  //    ontimer = 300;
      delay (10);
      ontimer = ontimer +1; //то добавляем 1 к таймеру
     }//else 3
//if 4
  }//if 3
  else //если нет питания
  {
  digitalWrite(ledPin2, LOW); //вырубаем
  ontimer = 0;//и обнуляем таймер.
  }
  
}//loop

 

 

4ERTIK
Offline
Зарегистрирован: 24.03.2013

Примерно так (если я понял правильно)

//реле включения с задержкой и выключения с задержкой
#define ledPin1 12  //Реле 1 - управление
#define ledPin2 11  //Реле 2 - управление

byte valA; //переменная времени 
byte flagA;
long previousMillisA = 0;

byte valB; //переменная времени 
byte flagB;
long previousMillisB = 0; 


void setup()    
{ 

  pinMode(ledPin1, OUTPUT); //иниц выхода
  pinMode(ledPin2, OUTPUT); //иниц выхода

} 

void loop() 

{ 
  //**************************первый таймер , включаемый через Н-секунд после нажатия**********************************
  if(digitalRead(8)==HIGH)//если кнопка нажата ... 
  { 
    flagA=1;
  }
  if(flagA==1)
  {

    if (millis() -previousMillisA >1000) 
    { 
      previousMillisA = millis();     
      valA++;                       // работает счет,ledPin1  выключен 
      digitalWrite(ledPin1,LOW); 
    } 
  } 

  if(valA>=5) //кол-во секунд((millis() -previousMillisA >1000) при достижении этого значения , ledPin1 включается
  { 
    digitalWrite(ledPin1,HIGH);


  }
  if(digitalRead(8)==LOW)//если кнопка не нажата ... 
  { 
    flagA=0;
    digitalWrite(ledPin1,LOW); //выключаем ledPin1 
    valA=0;//обнуляем переменную
  } 

  //********************************таймер второй*********************
  if(digitalRead(9)==HIGH)//если кнопка нажата ... 
  { 
    previousMillisB = millis();
    flagB=1;
    valB=0;
  }
  if(flagB==1)
  {
    digitalWrite(ledPin2,HIGH);
  }
  if(flagB==1&&digitalRead(9)==LOW)
  {

    if (millis() -previousMillisB >1000)
    { 
      previousMillisB = millis();     
      valB++;                       // работает счет,ledPin1  включен 
      //      digitalWrite(ledPin2,LOW); 
    }  
  }
  if(valB>=10) //кол-во секунд ,при достижении этого значения , ledPin2 выключается
  { 
    digitalWrite(ledPin2,LOW);
    flagB=0;
  }


}






 

deliter
Offline
Зарегистрирован: 18.06.2014

Привет! 4ettik, спасибо большое!

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

//реле включения с задержкой и выключения с задержкой
#define Relay_on_delay 12 //Реле 1 - управление
#define Relay_off_delay 11  //Реле 2 - управление
#define GreenLeds 10 // Светодиодная лента
#define LedButton 4 // Кнопка подсветки
#define Ignition 3 //вход сигнала зажигания
#define Generator 2 //вход сигнала генератора

byte valA; //переменная времени 
byte flagA;
long previousMillisA = 0;

byte valB; //переменная времени 
byte flagB;
long previousMillisB = 0; 

byte valC; //переменная времени 
byte flagC;
long previousMillisC = 0; 

int timer_on = 4; //включение 12вольт черех
int timer_off = 30; //выключение подсветки общей через
int timer_dimm = 5; //выключение подсветки байка через (ВНИМАНИЕ! Должно быть меньше timer_off!)

int ledState = LOW;         // После старта байка светодиод выключен
int buttonState = LOW;             // текущее состояние кнопки
int lastButtonState = LOW; // последнее состоянии кнопки

long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50; // the debounce time; increase if the output flickers

int dimm_value = 0; //начальное свечение = 0  
int dimm_time = 10; //время затухания
int greenLedState =1;
void setup()    
{ 

  pinMode(Relay_on_delay, OUTPUT); //иниц выхода
  pinMode(Relay_off_delay, OUTPUT); //иниц выхода
  pinMode(GreenLeds, OUTPUT);//иниц выхода pwm
  pinMode(LedButton, INPUT);
  pinMode(GreenLeds, OUTPUT);
//  analogWrite(GreenLeds, 0); //изначально выключено


  Serial.begin(9600);           // set up Serial library at 9600 bps
  Serial.println("Initialized setup");
  
  

} 

void loop() 
{//loop



//***************************выключение подсветки после выключения байка************
if (digitalRead(Ignition) == LOW && valB >= timer_dimm && greenLedState == 1 ) //вырубаем подсветку после глушения двигателя
{
  ledState = LOW;
  greenLedState = 0;
   Serial.println("time to turn off the leds"); 
     
}

  

//*****************************переключение подсветки*******************************

int reading = digitalRead(LedButton);

if (reading != lastButtonState) { //если положение кнопки изменилось то...
    lastDebounceTime = millis();
                                }//if 
  
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;
      if (buttonState == HIGH) {
        Serial.println("Button was pressed");
        ledState = !ledState;
        Serial.println(ledState);
      }
    }
  }
if (ledState == HIGH)// && greenLedState == 1)
{
  dimm_value = 255;
  analogWrite(GreenLeds, dimm_value);
 
}
else { 
  //Serial.println("666666666666666666");
 
  if (millis() -previousMillisC > dimm_time*4)
    { 
      if (dimm_value > 0)
    {
      previousMillisC = millis();     
      dimm_value--;
      Serial.println(dimm_value);
      analogWrite(GreenLeds, dimm_value);
      }
    }
    
      }
  lastButtonState = reading;
    


  //**************************первый таймер , включаемый через Н-секунд после нажатия**********************************
  if(digitalRead(Generator)==HIGH)//если кнопка нажата ... 
  { 
    flagA=1;
     Serial.println("Generator on");
  }
  if(flagA==1)
  {

    if (millis() -previousMillisA >1000) 
    { 
      previousMillisA = millis();     
      valA++;                       // работает счет,ledPin1  выключен 
      digitalWrite(Relay_on_delay,LOW); 
    } 
  } 

  if(valA>=timer_on) //кол-во секунд((millis() -previousMillisA >1000) при достижении этого значения , ledPin1 включается
  { 
    digitalWrite(Relay_on_delay,HIGH);


  }
  if(digitalRead(Generator)==LOW)//если кнопка не нажата ... 
  { 
    flagA=0;
    digitalWrite(Relay_on_delay,LOW); //выключаем ledPin1 
    valA=0;//обнуляем переменную
     
  } 

  //********************************таймер второй*********************
  if(digitalRead(Ignition)==HIGH)//если кнопка нажата ... 
  { 
    greenLedState = 1;
    previousMillisB = millis();
    flagB=1;
    valB=0;
  //  Serial.println("Ignition off");
  }
  if(flagB==1)
  {
    digitalWrite(Relay_off_delay,HIGH);
  }
  if(flagB==1&&digitalRead(Ignition)==LOW)
  {

    if (millis() -previousMillisB >1000)
    { 
      previousMillisB = millis();     
      valB++;                       // работает счет,ledPin1  включен 
      //      digitalWrite(ledPin2,LOW); 
    }  
  }
  if(valB>=timer_off) //кол-во секунд ,при достижении этого значения , ledPin2 выключается
  { 
    digitalWrite(Relay_off_delay,LOW);
    flagB=0;
  }

}





 

Leshiy
Offline
Зарегистрирован: 19.07.2014

Кнопки зависимы? Или их можно жать вместе, по отдельности и вообще по всякому? Если наэать на вторую кнопку в тот момент, когда вызванная ей процедура отсчёта 10 секунд работает, то что должно произойти: добавится ещё десять секунд, или ничего?

deliter
Offline
Зарегистрирован: 18.06.2014

Привет Leshiy!

В целом это не кнопки аа вводы (+5 воль, но можно и кнопки).

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

Для второго аналогично, если кнопку отпустить пойдет 5 секунд, нажать и отпустить - снова 5 секунд. 

Кнопки могут работать параллельно, кроме кнокри Dimmer_led.

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

 

Если что схема тут http://arduino.ru/forum/apparatnye-voprosy/pomogite-optimizirovat-skhemu

Leshiy
Offline
Зарегистрирован: 19.07.2014

Пример далеко не перл программистского искусства, но я и сам тот ещё программист.

/* Две кнопки, butt1 и butt2. 
   butt1 - нажатие приводит к зажиганию светодиода led1 на 5 секунд. 
           Нажатие во время свечения светодиода увеличивает время свечения светодиода на 5 секунд.
   butt2 - нажатие зажигает светодиод led2 на 10 секунд. Нажатие во время свечения светодиода увеличивает время свечения светодиода на 10 секунд.
  
   Также время свечения зависит от продолжительности нажатия на кнопку, то есть пока кнопка нажата светодиод не погаснет, 
   отсчёт времени до погасания начинается с момента отпускания кнопки. Функция успокоения (антидребезга) не включена в пример.
*/

#define ledPin1 12  //Реле 1 - управление
#define ledPin2 11  //Реле 2 - управление
#define butt1 2     //Вход, к которому подключена 1 кнопка, 5 сек.
#define butt2 3     //Вход, к которому подключена 2 кнопка, 10 сек.

unsigned long timerend[]={0,0};      // массив, в котором хранится время остановки таймера и гашения светодиода
int tdelay[]={5000,10000};           // задержка
int outpin[]={ledPin1,ledPin2};      // массивы tdelay, outpin и inpin должны быть заполнены так, чтобы ячейки вход-выход-задержка совпадали
int inpin[]={butt1, butt1};          // то есть в ячейке 0 должна быть триада вход-выход-задержка
int endcount=0;

void setup(){
  endcount =sizeof(inpin)/2-1;
  
  for (int i=0; i<=endcount; i++) 
  {
  pinMode(outpin[i], OUTPUT);
  pinMode(inpin[i], INPUT);
  digitalWrite(outpin[i], LOW);
  }
}

void loop(){
  
  for(int i=0; i<=endcount; i++){
    if (digitalRead(inpin[i]) == HIGH) {
        digitalWrite(outpin[i], HIGH);
        timerend[i]=millis()+tdelay[i];
    }
  }
  timer();
}

void timer(){
  
  for(int i=0; i<=endcount; i++){
    if (millis()>=timerend[i]) {
      digitalWrite(outpin[i], !digitalRead(outpin[i]));
    }
  }
}

 

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

>Пример далеко не перл программистского искусства, но я и сам тот ещё программист.
Да че... все прилично выглядит.... прицепится можно ну уж "совсем из принципа". Цепляться, что тут еще можно "замшевой тряпкой полировку навести"?

Leshiy
Offline
Зарегистрирован: 19.07.2014

А, там задержка на включение ещё нужна. Пропустил, прошу прощения, сутки уже без сна.

Leshiy
Offline
Зарегистрирован: 19.07.2014

leshak пишет:

>Пример далеко не перл программистского искусства, но я и сам тот ещё программист.
Да че... все прилично выглядит.... прицепится можно ну уж "совсем из принципа". Цепляться, что тут еще можно "замшевой тряпкой полировку навести"?

Спасибо, приятно слышать.

Движок у форума наистраннейший. В моём 28 фаерфоксе его корёжит страшно. Через строку пишу не потому, что шибко умный, а потому, что нажатие на Ентер приводит к появлению неудаляемой пустой строки. А браузер ради форума менять не комильфо, поэтому пишу в блокноте, а потом переношу сюда, так всё работает красиво.

Leshiy
Offline
Зарегистрирован: 19.07.2014

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

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

Не, я говорил про "стилистику".
Вот смотрите... Первое. Проверки типа
i<=endcount

Которые заставляют вас отнимать "магическую единицу", вот тут:
 

  endcount =sizeof(inpin)/2-1;

Математически - все верно. Вопросов - нет :)  Но... "так не принято". С такой привычкой и вам чужой код будет труднее читать, на ваш код другие будут морщится.
Делаем проверку
 

i<endcount

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

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

for(byte i=0;i<total;i++)

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

Leshiy
Offline
Зарегистрирован: 19.07.2014

leshak пишет:

Не, я говорил про "стилистику".
Вот смотрите... Первое. Проверки типа
i<=endcount

Которые заставляют вас отнимать "магическую единицу", вот тут:
 

  endcount =sizeof(inpin)/2-1;

Математически - все верно. Вопросов - нет :)  Но... "так не принято". С такой привычкой и вам чужой код будет труднее читать, на ваш код другие будут морщится.
Делаем проверку
 

i<endcount

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

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

for(byte i=0;i<total;i++)

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

Ясно. Ну я на "ардуино си" писать начал только когда ардуино купил, то есть полторы недели назад, так что я себя за эту ошибку прощаю. :)

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

Далее, конструкция вида:

 endcount =sizeof(inpin)/2;

(надеюсь на то что-бы убрать -1 я вас уже уговорил.
Что такое 2? Какая-то магическая цифра. Не... догадатся что это "размер одного элемента в байтах" - можно конечно. Но ведь это же мозг напрягать нужно :) Беглым взглядом "не ловится".
Тем более что оператор возвращающий размер "какой-нибудь фигни в байтах" - мы уже знаем. Поэтому и записать "размер массива поделить на размер элемета" мы можем практически буквально:

endcound=sizeof(inpin)/sizeof(int);

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

Кстати.... я бы inpin обозвал бы inpins , что-бы более явно было видно что это массив. множественное число - значит массив. можно даже в объявления не смотреть.

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

Leshiy пишет:

Ясно. Ну я на "ардуино си" писать начал только когда ардуино купил, то есть полторы недели назад, так что я себя за эту ошибку прощаю. :)


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

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

Далее, в setup()

pinMode(inpin[i], INPUT);
digitalWrite(outpin[i], LOW);

В принципе "спорный совет". Не ошибка. В какой-то степени даже "сам так люблю делать". Что-бы было явно видно, но....
Знайте что эти две строки не делают никакой полезной работы (кроме того что код чуть легче читается): по умолчанию, если ничего не далеть все пины уже включены как INPUT. И опять-таки, когда мы переключили кого-то на OUTPUT, то по умолочанию он уже LOW.

Вообщем делать так как сделали вы "можно", но делать нужно сознательно :)  Типа "вот такая прихоть автора" ;)

Leshiy
Offline
Зарегистрирован: 19.07.2014

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

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

Далее, в принципе вот этот endcount можно и не переменной делать.
Можно его тоже как define объявить...(сразу переименую его в TOTAL)

#define TOTAL sizeof(inpin)/sizeof(int) 

Что это дает?  Так как на этапе компиляции и размер массива и размер int-та, уже известен. То компилятор сразу поделит одно на другое, и сразу подствит во все места где вы используете этот макрос: итоговую цифру.
Как будто вы руками написали
for(int i=0;i<2;i++)

Мы получим экономю в два байта (не будет выделения памяти для переменно) и экономию в пару тактов процессора на чтение этой переменной из памяти.

Leshiy
Offline
Зарегистрирован: 19.07.2014

leshak пишет:

Далее, в setup()

pinMode(inpin[i], INPUT);
digitalWrite(outpin[i], LOW);

В принципе "спорный совет". Не ошибка. В какой-то степени даже "сам так люблю делать". Что-бы было явно видно, но....
Знайте что эти две строки не делают никакой полезной работы (кроме того что код чуть легче читается): по умолчанию, если ничего не далеть все пины уже включены как INPUT. И опять-таки, когда мы переключили кого-то на OUTPUT, то по умолочанию он уже LOW.

Вообщем делать так как сделали вы "можно", но делать нужно сознательно :)  Типа "вот такая прихоть автора" ;)

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

Про #define узнал пару дней назад и ещё не приучил себя к ним. Переменные пока роднее.

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

Еще плюсом вычисления TOTAL с помощью #define состоит в том, что мы можем использовать его при объвялении других массивов.

Скажем писать:

int outpin[TOTAL]={....}

Зачем это нужно? Зачем в явном виде говорить размер массива? А затем, что если мы вычилсли TOTAL на базе inpin массива, а потом попытаемся в oupin проинициализировать больше количество элементов, то компилятор на нас ругнется. Впихнуть в outpin элементов больше чем в inpin - мы уже не сможем.  (меньше - к сожалению сможем. но хоть в одну сторону нас компилятор подстрахует).

Leshiy
Offline
Зарегистрирован: 19.07.2014

Верно. Я хотел сделать проверку на размер, но решил, что в примере оно не надо. Хотел потому, что  своём небольшом проекте, ради которого я и купил ардуино и начал учить язык, я допустил ошибку, внеся в мастер-массив элементов больше, чем с слейв-массив. И тут такооое началось! я часа полтора потратил, пока допёрло что и как (потому что ночью надо спать, а не быдлокодить).

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

Leshiy пишет:

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

Ну так все мы так осваиваем :) Все норм.
sizeof(int) имеет еще и один такой существенный плюс: вы увеличиваете переносимость.
На другом камне, с другим компилятором.... int может иметь размер совсем не 2-байта. Скорее 4-байта это более частая ситуация. Если вы "жестко забили делению на двойку", то на другой платформе "все пойдет лесом". И если программа большая то найти все эти деления на двойку, будет... ой как не просто.

А sizeof(int) - все продолжит работать как и планировалос. А "перейти на другую платформу" может оказаться не таким уже "фантастическим делом". Например будете писать какой-то уж слишком сложный алгоритм/фильтр/сортировку. На ардуине из-за отсуствия нормального дебагера - неудобно. Можно эту функцию написать отладить на большом компе, а потом просто сделать copy-pastе на ардуину.

Кстати про размер int-та. Два байта. Давайте привыкать экономить. Чай микроконтроллер у нас. Планку памяти просто так не доставишь.
Итак, какой у нас самый большой возможный номер пина?  В случае меги 54. И отрицательных пинов у нас не бывает. Поэтому int - в даном случае "расточительство". Хватит обычного byte. Который от 0 до 255.
И для хранения номеров пинов, и для счетчиков циклов и т.п.

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

Leshiy пишет:

 я часа полтора потратил, пока допёрло что и как (потому что ночью надо спать, а не быдлокодить).

О... ну значит вы уже "битый". Уже не нужно объяснять почему время потраченное на "выработку стиля" - окупается сторицей :)

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

Кстати постоянное привычка сознательно думать "какой тип тут лучше выбрать" - тоже уберегает (хотя и не 100%) от многочасовых поисков траблов. А если привык лепить "int" не думая, то где-то... в итоге... и таки напишешь int time=millis();   :(
 

Leshiy
Offline
Зарегистрирован: 19.07.2014

Проблема в эпизодичности подобной работы. Сляпал и красотааа! Поэтому о выработке стиля говорить не приходится, хотя, конечно, он многое решает. Больше всего не люблю что-то делать ради самого процесса, поэтому "включаюсь" только если что-то надо изготовить, или изобрести этакое, тогда интересно. В остальное время предпочитаю сибаритствовать.

Нее, int к millis не моё. Оно ведь работать должно, а не коекакить. А вот переменные могу называть так, как мне удобнее в данном случае, тут я не придерживаюсь линии партии об именовании. Вот с миллис у меня небольшая нелюбовь, она, зараза, склонна к полноте и, даже, переполнению. А железка моя должна работать постоянно, RTC не хочу, батарейки фи, аккум можно, но тоже не вечен. Пока думаю ресетить дуину по прошествии 30 дней, при условии стабильного состояния устройства. Правда надо посмотреть, что по выходам при ресете происходит, а то меня 13 моргающий напрягает. Если и все остальные выходи не в выскоимпеданс уходят, а начинают дрыгать уровнями, то аяй.

А хочу ещё советов! Я уже их в папочку сложил, абсолютно серьёзно. Завтра зубрить буду. Про байт - замечательно, у меня вообще с типами проблемы, их надо решать.

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

Дальше... вы на горьком опыте познали как плохо когда массивы которые должны быть одного размера,  "рассогласовались".
В сторону slave больше master - мы уже знаем как подстраховатся, но... "меньше" - нет у нас рецепта. И, поверте, если ошибка возможна - она случится.
А какая деталь не может сломаться? Правильно - та которой нет.
Значит нам нужно сделать так, что бы у нас небыло кучи разных массивов, за согласованием размеров которых нужно сделить.
Вот был-бы у нас всего один массив.... длина одиного всегда же равена своей собственно длине :) Сделать ошибку - шансов нет.
Как же нам запаковать разнородные данные в один массив?
А объеденить "что-то различное" в одну сущность нам позволяет конструкция языка struct.
Потом мы объявлем массив этих структур и... дело в шляпе.

Посмотреть пример структры можете тут (там объединят три числа r,g,b для одного светика в одну сущность)
Arduino Playground - Struct Resource

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

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

 

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

Ну так "стиль" он для того и нужен. Что-бы рутинные операции выполнялись без напряжения мозгов (больше времени на сибаритсво) и при этом качество не страдало (небыло кое-какерства).
Это сейчас вас очевидно что inpin - это массив.
А через пол-годига, когда стрехнете со скетча пыль - уже нужно лезть смотреть в объвления. А так сразу понятно - множественное число.
Опять-таки функцию какую-то захотите написать. У которйо будет параметр "входной пин". Как его обзовете? inpin. Хоп. Конфликт имен с массивом. И хорошо если компилятор завопит. А ведь бывают случае когда "все прошло тихо", только поменялась не та переменная которую хотели... Вернее другая переменная почему-то "начала менятся". И выяснить "какая падла ее меняет" это уже не часы, а дни и недели могут быть.
Так что имена переменных и функций это не "как хочу так и ворочу", а одно из самых важных (и кстати самых сложных). Именно от них зависит читаемость и сопровождаемость кода.

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

— Martin Golding

 

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

>Пока думаю ресетить дуину по прошествии 30 дней

Фу...Фу.. Думать забудте.
Если спросите на форуме, то либо засмеют, либо в такие дебри заведут.... если не верите, то поищите ветку соотвествующую :) И того и другого там будет вдосталь. И смеха и дебрей... вплоть до шансов "а!!! теперь в ардуину не заливаются скетчи.." :)

С millis() проблема решается гораздо проще, примерно так как и с i<=encount, просто нужно привыкнуть к другой конструкции.
Которая "математически эквивалентна", но... не имеет проблем с переполнением.
Смотрите базовый пример Мигаем светодиодом без delay()
Смотрите как там делается проверка "нужный интервал времени прошел". Такой способ - через вычитание, а не суммирование... будет работать и через 50-т дней. 

Leshiy
Offline
Зарегистрирован: 19.07.2014

Почитал, более-менее понял, но возник вопрос: почему структура, а не многомерный массив? Структура более наглядна, меньше\столько же жрёт памяти, в этом причина?

Leshiy
Offline
Зарегистрирован: 19.07.2014

leshak пишет:

>Пока думаю ресетить дуину по прошествии 30 дней

Фу...Фу.. Думать забудте.
Если спросите на форуме, то либо засмеют, либо в такие дебри заведут.... если не верите, то поищите ветку соотвествующую :) И того и другого там будет вдосталь. И смеха и дебрей... вплоть до шансов "а!!! теперь в ардуину не заливаются скетчи.." :)

С millis() проблема решается гораздо проще, примерно так как и с i<=encount, просто нужно привыкнуть к другой конструкции.
Которая "математически эквивалентна", но... не имеет проблем с переполнением.
Смотрите базовый пример Мигаем светодиодом без delay()
Смотрите как там делается проверка "нужный интервал времени прошел". Такой способ - через вычитание, а не суммирование... будет работать и через 50-т дней. 

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

Глянул, опять поморгаем светиком... Пусть они светиком 50 дней поморгают, при этом в проекте, в котором если светик не моргнёт в нужный момент, то разработчику сразу сапогом в табло прилетит, тогда и посмотрим... Запомнили мы ТЕКУЩЕЕ значение millis(), программа что-то там поделала и думает, надо бы нам посмотреть, сколько времени прошло-то, а то мож уже пора атомную бомбу отключать, чтоб не бахнула. Берёт она millis() и вычитает из неё предыдущее значение, тут кэээээк бабахнет! И абзац. А бабахнуло потому, что миллис у нас обнулится изволила, переполнилась и через края пошло. Поэтому она всё слила и теперь равна 10. А ПРЕДЫДУЩЕЕ значение было равно стомиллионмиллиардов миллисекунд.

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

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

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

Leshiy пишет:

Почитал, более-менее понял, но возник вопрос: почему структура, а не многомерный массив? Структура более наглядна, меньше\столько же жрёт памяти, в этом причина?

О :) Теперь у вас два "домашних задания" ;)
Сделать структурами и сделать многомерным массивом.
Кто памяти больше жрет... у вас уже есть "волшебный инструмент" sizeof()
Кто наглядней - вот выложите оба варианта, посмотрим/сравним/обсудим ;)

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

Leshiy пишет:

 Берёт она millis() и вычитает из неё предыдущее значение, тут кэээээк бабахнет! И абзац. А бабахнуло потому, что миллис у нас обнулится изволила, переполнилась и через края пошло. Поэтому она всё слила и теперь равна 10. А ПРЕДЫДУЩЕЕ значение было равно стомиллионмиллиардов миллисекунд.

О... а вот и ваше третье домашние задание ;) Не теоретизировать а поставить эксперемент. Проверить "бабахнет или нет". Смодулируйте ситуацию. Сделайте три переменных unsigned long. В одну положите "текущие значение millis()" - 10. Во вторую, прошлое значение "стомиллионмиллиардов миллисекунд". Потом вычтите из первой вторую (аналог millis()-prevTime), поместитите в третью переменную разница (diff). Сделаейте Serial.println(diff).... и расскажите нам. Бабахнуло или, все-таки,  нет :)

Leshiy
Offline
Зарегистрирован: 19.07.2014

Бабахало уже. При старте дуины millis == 0, а код уже шустрить начал всякое, и первое вычитание происходит при millis == 100-200ms, а вычитается из них 15000мс, какая красота в терминале при этом образуется, просто неописуемо. Пока обошёл вводом переменной trumillis, которая всегда равна miillis()+60000. А третью домашку щаааа, это не со структурами ковыряться.

Ожидаемая дикая дичь.

unsigned long last=1000;
unsigned long current=0;
unsigned long diff=0;

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

void loop(){
current=millis();
diff=current-last;
Serial.println(diff);

if diff<=1000 {
 boolean A_Bomb_Launch=false
 Serial.println("А может бахнем? - Обязательно бахнем... Но потом.");
}
else{
 A_Bomb_Launch=true
 Serial.println("Весь мир в труху!");
}

Вывод:

773
92064294966296
4294966296
4294966297
4294966297
4294966298
4294966298
4294966303
4294966315
4294966328
4294966341
4294966353
4294966365
4294966377
4294966390
4294966403
4294966415
4294966428
4294966440
4294966452
4294966465
4294966478
4294966490
4294966502
4294966515
4294966528
4294966540
4294966553
4294966565
4294966577
4294966589
4294966603
4294966615
4294966627
4294966640
4294966652
4294966665
4294966677
4294966690
4294966702
4294966714
4294966728
4294966740
4294966752
4294966764
4294966777
4294966789
4294966802
4294966815
4294966827
4294966839
4294966852
4294966865
4294966877
4294966889
4294966902
4294966914
4294966927
4294966940
4294966952
4294966964
4294966976
4294966989
4294967002
4294967014
4294967027
4294967039
4294967051
4294967065
4294967077
4294967089
4294967101
4294967114
4294967127
4294967139
4294967152
4294967164
4294967176
4294967188
4294967202
4294967214
4294967226
4294967239
4294967251
4294967264
4294967276
4294967289
5
8
11
15
19
24
28
33
37
41

 

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

Leshiy пишет:

Ожидаемая дикая дичь.

Почему ожидаемая? Что вы сейчас сэмулировали?  Ну что за "пируэты на граблях"? :) 
Зачем использовали millis(), когда сказанно было "положите в переменные".
Вам что нужно было? Проверить как произойдет вычисление интервала после переполнения. Правильно или нет.
1000 и простите "стомиллионов-миллисекунд" это слегка разные вещи.

Нужно было просто в две переменные, положить два значения. Отнять и вывсести. Один раз... что-бы понять "что происходит". Зачем это в loop() попало? Что-бы самому нельзя было "на пальцах" перепроверить верно ли сработало наше вычитание?

Раз мы воспроизводим ситуацию "переполнение", значит и значения для теста мы должны подбирать "близкие к правде". Предположим у нас last было записанно за "10-сек до переполнения". Это какое значение millis()?  4294967295-10000=4294957295
Вот его и пложите в last.
Теперь, предположим у на текущие время "2 секунды после переполнения". Значит ложим в current=2000;
Отнимаем одно от другого и выводим. Для проверки "считаем на пальцах". Сколько "взаправду прошло времени" от прошлого last?  "10 сек до переполнения, 2 сек. после". Вместе получается 12сек. Если наш код насчитает при таких last и current что прошло "12 секунд" значит проблема переполнения его не затронула. Логично? (на самом деле 12 секунд и одна миллисекунда. само "переполнение" тоже одну миллисекунду занимает).

 

unsigned long last=4294957295;
unsigned long current=2000;
unsigned long diff;

void setup(){
Serial.begin(57600);
diff=current-last;
Serial.println(diff);
}

void loop(){}

 

 

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

А то что вы "наэксперементировали", так это простите вы уже переполнились самими интервалами. Посчитайте "на пальцах" какой же временной интервал "взаправду" получился в вашем случае... и мог-ли он поместиться в unsigned long.
Вернее мог конечно, и вначале помещался... и даже верно выводился. Только вы этого - не поняли. Что вот эти "большие числа", а не бред, а именно то сколько времени прошло при данных вами входных параметрах. Просто ставя эксперимент нужно было прикинуть сколько же вы ожидаете в качестве "корректного результата". 
Что вы ему дали?  То что как был записан last , до переполнение прошло 49 девять с копейкой дней. После переполнения - пару секунд.
Ну... и какая должна быть разница? 49 девять с чем-то дней. Что-то близкое к максимального unsigned long. Что вообщем то мы и увидели в вашем выводе.
Вообщем "а вы чего ожидали"? ;)

Leshiy
Offline
Зарегистрирован: 19.07.2014

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

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

Да, к вопросу о том, что мне нужно: мне нужно, чтобы оно работало. Выяснилось, что переполнение обрабатывается корректно, это хорошо, завтра буду думать, как красиво обойти проблему с уходом в псевдоотрицательные числа, потому как millis()+60000 это костыляка та ещё.

И я прекрасно понял, что большие числа не бред, я просто не понял, шо мне пока с ними делать, так как операция, от которой программа ожидает чего-то типа 0, возврашает ей 120938230498, ессно программа дичает и начинает плохо пахнуть. Но, собственно, это проблема не программы, а её написателя.

Leshiy
Offline
Зарегистрирован: 19.07.2014

Вот теперь сон не идёт... В общем в моём случае при условии last>current, надо менять знак числа, которое вычитается из current. И всё, похоже.

if (last>current) { //если mills переполнилась
  diff=current-(-15000);
}
else{ //если нет
  diff=current-15000;
}

Пример так, для иллюстрации идеи.

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

Leshiy пишет:

Пример так, для иллюстрации идеи.

Стремная какая-то идея. Какие-то попытки "угадать правильное заклинание". Никакие плюсы тут не нужны. Какой в плюсе реальный "физический смысл"?
Разница между currentTime-prevTime нам дает в результате "сколько времени прошло между prevTime и currentTime". Независимо от того "было-ли между ними переполнение" или нет. Независимо от того кто из них больше/меньше...  
Естественно это работает только в случае когда currentTime, prevTime и разница - одного БЕЗЗНАКОГО тип. И переполнение было только одно. И если currentTime не "обгонял" prevTime (это то что произошло в вашем эксперименте через секунду и появились "маленькие цифры" - вот они и были "неправильными"). Если он "догнал prevTime", то действительно возникает неоднозначность. По разнице мы уже понять не можем мы "только что начали отсчет" или currenTime успел сделать круг (или несколько). Но... если он его "обогнал", это значит что сама разница "сколько прошло времени" уже не помещается в unsigned long. И нам нужно будет для вычисления "сколько прошло времени" пользоваться уже более вместительными типами. Или... если мы хотим делать часы или еще что-то подобное (при этом нас не колышит точность. плюс/минус километр устраивает), то нам нужно будет завести отдельную переменную, в которой мы будем засекать "сколько кругов прошел currentTime". Но круги мы, опять-таки, будем отсчитывать детектирую не "переполнение", а моменты когда currentTime сравнивается с prevTime.
Но... в 99% процентах задач. Нам не нужно ловить интервалы, мигать диодом с переодичностью в 50-т дней.
Практически всегда нам нужны интервалы в секунды/миллисекунды. Что совершенно спокойно помещается в unsigned long. А значит можно делать простое вычитаение стартового времени и текущего. И не переусложнять свой код.

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

Вообщем, что-бы было легче мысленно представить "почему же разница работает".
Вообразите себе 12-ти часовй циферблад (только вместо 12-ти у нас ноль). Вообщем имеет 12-ть "засечек" 0..11
Ситуация 1:
Первая стрелка у нас стоит на 10-ти часах. это prevTime
Вторая стрелка у нас стот на 11 часах. это currentTime
Третья на нуле - это "разница" (мы ее пока не высчитали).

Отнимаем currentTime-prevTime=11-10=1. Переполнение небыло. Все очевидно. Теперь просто крутим третью стрелку по часовому направлению на одно деление. Все наш "прибор" показал что между currentTime и prevTime прошел ровно один час (показание третьей стрелки).

Ситуация 2:
Возвращаем третью стрелку (diff) в нулевую позицию... (пока не выщитана разница). diff=0
prevTime тоже самое что и в прошлом примере prevTime=10
А вот currentTime у нас пошел "тикать" дальше.... прошел 0 (12ть часов), это случилось "переполнение", 1,2,3 и остановился на "трех часах". Мы опять делаем ТО ЖЕ САМОЕ
currentTime-prevTime=3-10=-7
Теперь нам нужно выставить третью стрелку, в "минус 7мь часов". Но.... у нас же нет на циферблате "отрицательных чисел" (как их нет и в unsigned long, поэтому нам важна беззнаковость типа куда мы разницу сохраняем). Но... абсолютно как и в прошлом случае, мы просто крутим diff-стрелку на нужное количество делений. Просто раз отрицательное число, крутим ее "против часовой стрелки". На семь делений.
11,10,9,8,7,6,5 - и остановились на 5-ти часах.
Итого наш прибор показал (показаниея третьей стрелки) что между 10-тью часами и тремя часами - прошло 5-ть часов. Что соотвествует правде (2 часа "до полуночи" плюс три часа "после полуночи").

И все у нас будет хорошо, пока currentTime не "дотикает" до 10-ти часов. До места где стоит "prevTime". В этот момент обнулиться diff.
Если же, мы хотя-бы раз, пока currentTime не догнал prevTime обновили саму prevTime на "свежее время", то.... у нас нет проблем.

Как еще более "понятней" рассказать - я не знаю... разве что "нарисовать", но сейчас точно на это нет времени :)

Вообщем весь фокус работает потому что "разница отрицательная", а когда мы пытаемся запихнуть "отрицательно" в беззнаковый тип unsigned long. Мы получаем "второе переполнение" в обратную сторону. Одно переполнение, компенсирует другое и на выходе: корректный результат.

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

Leshiy пишет:

Вот теперь сон не идёт... В общем в моём случае при условии last>current, надо менять знак числа, которое вычитается из current. И всё, похоже.

if (last>current) { //если mills переполнилась
  diff=current-(-15000);
}
else{ //если нет
  diff=current-15000;
}

Пример так, для иллюстрации идеи.

вы сможете перевести на челЯзык - время абсолютное = 15 ч 75 мин 65 сек ? если сможете - то переложите это на МИЛЛИС :) , НО - миллис легко отследить при периоде засечки времени не более 1,9 ( например ) периода переполнения счётчика миллис.... при более длительных отрезков времени - придётся учитывать количество переполнений миллис...

по логике Лешака продолжу....

- в 23:00 засекли время

- в 23:59:59,999999999 и ещё чуть-чуть произошло переполнение миллис и стало =0

- в 01:00 фиксируем время

- diff = 01:00 - 23:00 = -22:00

- через if -> если ( diff < 0 ) то корректируем diff ! diff = diff + 24:00 = -22 + 24 = 2 часа

....от 23 до 01 - именно 2 часа

!!!!!!!!! если переполнения отследить, то нужно учесть их количество - ЧТО НЕ ТАК ?

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

ЦИКЛ переполнения миллиса - есть цикл ! мне кажется ( я уверен ), ( мине хочется верить ) - что при переполнении миллиса не добавляется никаких аппаратных тактов.... время не искажается.... счётчику - что переключиться с 16789 на 16789, что с 25678 на 0 - одно и тоже.... числа - не в тему - неохота вспоминать макс значение миллис :( , типа - 25678 = макс значение счётчика миллис ( только для этого поста ! )

итого, или как ещё рассудить-то ?

- миллис в ардуине - это абсолютное время

- если засечки времени относительного меньше периода переполнения счётчика миллис ( абсолютное время ) - то нет никаких проблем

- иначе - организуйте учёт колво переполнений ( N ) и скорректируйте время относительное на N циклов переполнения

......тема похожа на тему "1999 -> 2000", мир не рухнул же :)

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

Вообщем весь фокус работает потому что "разница отрицательная", а когда мы пытаемся запихнуть "отрицательно" в беззнаковый тип unsigned long. Мы получаем "второе переполнение" в обратную сторону. Одно переполнение, компенсирует другое и на выходе: корректный результат.

.......через IF - для таких как моя :) , фокус Лешака - от знаний представления чисел.... блиииин, действительно минус на минус  = правильно :)

Leshiy
Offline
Зарегистрирован: 19.07.2014

Во вы накрутили!!! :) Всё, кагбэ, уже давно исделано - проблема была только в несоответствии типов.

Если из unsigned long вычитать int, то есть millis=100, а мы делаем millis-1000, то выходят бока, "псевдоотрицательные" числа. А если мы объявим unsigned long diff=1000; unsigned long decrement=10000 и сделаем if (millis-decrement)>diff {}, то всё выходит как задумано.

То есть не if (millis-10000)>diff{}, а именно if (millis-decrement)>diff {}

Если точнее, то можно и инт вычитать, но не нужно.

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

зачем вы привязались к какой-то 10000 ? "...if (millis-10000)>diff{}..."

есть только мигЗафиксированный, и мигТекущий, нууууу, и разница вычисляемая....

миг-29 - это другое....

:)-

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

через фокусы Лешака ( знаковый / беззнаковый ) - это к Лешаку..... моя объяснить пытался через "если diff < 0", в итоге - это одно и тоже !!!!!!!!!!!!! .....в диапазоне одного переполнения !!!!!!!!!!!!!!!

Leshiy
Offline
Зарегистрирован: 19.07.2014

Больше восклицательных знаков, боольше! :)

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

согласен.... колво !!!!!!!!!!!!!!!!!!!!! - просто эмоции.... лишнее т.е. ..... спасибо за критику :)

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

А если мы объявим unsigned long diff=1000;

запутали.... зачем назначать diff=1000 ? это же ВЫЧИСЛЯЕМОЕ значение :( ....оно до первой засечки времени - неопределено

Leshiy
Offline
Зарегистрирован: 19.07.2014

diff=1000 чисто для внесения в скушную нашу жизнь свежей струи!

Домучал я свой "проект", работает сносно вполне, то есть делает то, что нужно тогда когда нужно. Сейчас засел за его переработку в соответствии с высокими стандартами программирования - val, byte, diff и остальные страшные буквы. Тако же во имя Разума и Знаний приступил ко изучению Великих Структур. Так как Великие Структуры начал изучать... эээ... минут пять назад, ещё не понял, можно ли к членам структуры обращаться не по имени, а по нумеру их. А то с циклами печально как-то всё выходит. В общем жизнь идёт.

2 leshak
Ещё 5 минут поизучал. Структура дело нужное, только вот что она на даст в рассматриваемом случае с двумя таймерами? Объявим по структуре на каждую кнопку, которая будет управлять таймером? Или вы предлагаете создать структуру из массивов? Или многомерную структуру, если такое вообще возможно, я ваще не в кугсе, пацаны.

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

Leshiy пишет:

- в 23:59:59,999999999 и ещё чуть-чуть произошло переполнение миллис и стало =0

Шо вы накрутили? Вы мысленный эксперимент с циферблатами поставили? Какие 23:59:59?
Сказанно же было 12-ть засечек. От 0 до 11.
Никаких дробных. Целые числа.
У millis() - тоже "только целые".
Только положительные. Никаких дробных. Никаких отрицательных.

Зачем вы вначале "по простому" в голове уложите, а потом уже в сторону усложнений пойдете.
 

Leshiy
Offline
Зарегистрирован: 19.07.2014

leshak пишет:

Leshiy пишет:

- в 23:59:59,999999999 и ещё чуть-чуть произошло переполнение миллис и стало =0

Шо вы накрутили? Вы мысленный эксперимент с циферблатами поставили? Какие 23:59:59?
Сказанно же было 12-ть засечек. От 0 до 11.
Никаких дробных. Целые числа.
У millis() - тоже "только целые".
Только положительные. Никаких дробных. Никаких отрицательных.

Зачем вы вначале "по простому" в голове уложите, а потом уже в сторону усложнений пойдете.
 

Я не то, что не поставил, я даже не читал. К тому же не припомню, где я про 23:59:59 писал.

Лучше про структуры расскажите, про конкретное применение в данном случае. Я не понимаю их смысла здесь, на каждую кнопку по структуре объявлять, вы это имели ввиду?

deliter
Offline
Зарегистрирован: 18.06.2014

Жестяк ребята, я от вашей переписки узнал больше чем от 5и курсов иснтутиту...