Help. Переполнение значения переменной типа unsigned long!!!!!!

logpro
Offline
Зарегистрирован: 18.08.2013
Всем кто читает это, здравствуйте.
​Прошу помощи у более опытных программеров. Имею нижеприведенный скетч для сравнения текущего времени с заданным
Скетч работает в составе програмного кода управления баней.

byte CompTime(int HR, int MIN)        //Передаваемые параметры HR, MIN Возвращаемое значение ResultTime
{
  byte ResultTime;
  unsigned long InstTime = (HR * 60 * 60 + MIN * 60);                                      //Переводим пороговое время в количество секунд от начала суток
  clock.getTime();
  byte SEC = clock.second;
  MIN = clock.minute;
  HR = clock.hour;
  unsigned long NowTime = (HR * 60 * 60 + MIN * 60 + SEC);                                 //Переводим текущее время в количество секунд от начала суток
  if (NowTime > InstTime)  ResultTime = true; else                                         //Если текущее время больше порогового, возвращаем логическую единицу
      if (NowTime < InstTime)  ResultTime = false; else                                    //Если текущее время меньше порогового, возвращаем логический ноль
      if (NowTime == InstTime)                                                             //Если текущее время равно пороговому, возвращаем значение "2"
      {
        ResultTime = 2; delay(750);                                                        //Ждем 750 мСек для того чтобы цикл не успел повториться в течение этой секунды 
      }
  return ResultTime;
}

Проблема в том что в строке 8 значение InstTime никогда не превышает 65535, т.е  приблизительно в 18:12 переменная приобретает значение 0, хотя предельное значение переменной типа unsigned long равно 4 294 967 295

В строке 13 переменная NowTime имеет значение 4 294 967 295 уже приблизительно в 11:56, далее знчение становится равным 0 и отсчет начинается снова, хотя в сутках всего 86400 секунд

Путем подбора различных способов реализации алгоритма скетч трансформировался в следующий:

  byte CompTime(byte HrIns, byte MinIns)        //Передаваемые параметры HR, MIN Возвращаемое значение ResultTime
  {
    byte ResultTime;
    clock.getTime();
    byte HR = clock.hour; 
    byte MIN = clock.minute;
    byte SEC = clock.second;                                 
    unsigned int m = HR*60;
    unsigned long NowTime = m * 60 + MIN*60 + SEC;                                                 //Переводим текущее время в количество секунд от начала суток
    unsigned long InstTime = MinIns*60 + 60*HrIns*60;                                                      //Переводим пороговое время в количество секунд от начала суток
    if (NowTime > InstTime)  ResultTime = true; else                                         //Если текущее время больше порогового, возвращаем логическую единицу
    if (NowTime == InstTime)                                                               //Если текущее время равно пороговому, возвращаем значение "2"
    {
      ResultTime = 2; delay(750);                                                            //Ждем 750 мСек для того чтобы этот цикл не успел повториться в течение этой секунды пока время 21:00 
    } else
    if (NowTime < InstTime)  ResultTime = false;                                              //Если текущее время меньше порогового, возвращаем логический ноль
    return ResultTime;
  }

Проблема с переполнением NowTime изчезла, однако InstTime победить не удалось ни таким ни другими способами.

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

Плата Arduino Mega, пробовал компилировать в средах 1.0.6, 1.6.6, 1.8.2 с одинаковым результатом

Заранее благодарен откликнувшимся

logpro
Offline
Зарегистрирован: 18.08.2013

Значение HR и Min не превышает 59. Поэтому эти переменные и объявлены как Int в строке 5

Или не про это?

b707
Offline
Зарегистрирован: 26.05.2017

logpro пишет:

Проблема с переполнением NowTime изчезла, однако InstTime победить не удалось ни таким ни другими способами.

надо так:

unsigned long InstTime = MinIns*60UL + 60*HrIns*60UL;    
   

Иначе у вас вычисления идут в размерности byte, а не unsigned long

 

logpro
Offline
Зарегистрирован: 18.08.2013

Спасибо громадное. Завтра попробую. Чую что вы правы.

bwn
Offline
Зарегистрирован: 25.08.2014

Вставляйте сериалы, мониторьте значения переменных и результатов вычислений с ними. Где то косяк и вынырнет. Ну никак в этих формулах лонга не переполнить.

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

bwn, не разу не сталкивались с такой ситуацией? :) Можно конечно как советовал b707, но как тогда решить пример где все множители уже заданные переменные. Например так:

byte a=100, b=100,c=100;
 unsigned long n = a*b*c;  //так будет хрень
Serial.println(n); 
 

Поэтому лучше всегда объявлять тип данных для обоих половин выражений:

unsigned long n = (unsigned long) a*b*c; //так правильно
  

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

dimax пишет:

Поэтому лучше всегда объявлять тип данных для обоих половин выражений:

unsigned long n = (unsigned long) a*b*c; //так правильно  

"обеих половин выражений" не совсем точно. В Вашем примере тип объявлен только для a. А вот если действительно сделать "дл половины выражения" (unsigned long) (a*b*c), то опять же будет хрень.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

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

Самый грамотный вариант решения - у b707.

bwn
Offline
Зарегистрирован: 25.08.2014

dimax пишет:

bwn, не разу не сталкивались с такой ситуацией? :) Можно конечно как советовал b707, но как тогда решить пример где все множители уже заданные переменные. Например так:

Бог миловал.))) Пока писал свой ответ, прилетели все предыдущие, прочитал их позже. Править не стал, решил, что мониторинг сериалом все равно не повредит. 
А так, да, если ни разу не наступил на грабли, это еще не значит, что их нет.(((( Каюсь.

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

1090034.jpg

logpro
Offline
Зарегистрирован: 18.08.2013

Спасибо b707 за помощь. Все получилось. Верно говорят Век живи, век учись.

pvakos
Offline
Зарегистрирован: 21.07.2019

Пожалуйста помогите! 

#include <TimeLib.h>
#include <DS1307RTC.h> // датчик времени подкл SDA-А4, SCL-А5
tmElements_t tm;       // назначил tm как элемент текущ времени

// Печать в порт строки с параметром
void SerPrnt(String S, int prmt)
{
  Serial.print(S + " =");
  Serial.println(prmt);
}
void setup() {
 Serial.begin(9600);
 RTC.read(tm); // текущее время 18:32
  unsigned long t1 = tm.Hour;
  unsigned long t2 = tm.Minute;
  unsigned long t3 = (unsigned long)t1*3600UL;
  unsigned long t4 = t2 * 60;
  SerPrnt("t1", t1); //результат 18
  SerPrnt("t2", t2); //результат 32
  SerPrnt("t3", t3); //результат -736 ?????? НУ КАК ТАК-ТО ????
  SerPrnt("t4", t4); //результат 1920 (=18*60)
}

void loop() {

}

 

mixail844
Offline
Зарегистрирован: 30.04.2012
запустите данный код, удивитесь

void setup ()
{
Serial.begin(9600);
Serial.println(sizeof(long));
Serial.println(sizeof(int));

}

void loop()
{

}

 

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

pvakos пишет:

Пожалуйста помогите! 

Как говорится, если человек идиот, то это надолго. И никто в этом не поможет.

#include <TimeLib.h>
#include <DS1307RTC.h> // датчик времени подкл SDA-А4, SCL-А5
tmElements_t tm;       // назначил tm как элемент текущ времени

// Печать в порт строки с параметром
void SerPrnt(String S, int prmt)//<- обратите на это int prmt
/* ддя тех ктов танке то идет преобразоваете из любого типа в int*/
{
  Serial.print(S + " =");
  Serial.println(prmt);
}
void setup() {
 Serial.begin(9600);
 RTC.read(tm); // текущее время 18:32
  unsigned long t1 = tm.Hour;
  unsigned long t2 = tm.Minute;
  unsigned long t3 = (unsigned long)t1*3600UL;
  unsigned long t4 = t2 * 60;
  SerPrnt("t1", t1); //результат 18
  SerPrnt("t2", t2); //результат 32
  SerPrnt("t3", t3); //результат -736 ?????? НУ КАК ТАК-ТО ????
  SerPrnt("t4", t4); //результат 1920 (=18*60)
}

void loop() {

}

 

Kakmyc
Offline
Зарегистрирован: 15.01.2018

pvakos пишет:

Пожалуйста помогите! 

#include <TimeLib.h>
#include <DS1307RTC.h> // датчик времени подкл SDA-А4, SCL-А5
tmElements_t tm;       // назначил tm как элемент текущ времени

// Печать в порт строки с параметром
void SerPrnt(String S, int prmt)
{
  Serial.print(S + " =");
  Serial.println(prmt);
}
void setup() {
 Serial.begin(9600);
 RTC.read(tm); // текущее время 18:32
  unsigned long t1 = tm.Hour;
  unsigned long t2 = tm.Minute;
  unsigned long t3 = (unsigned long)t1*3600UL;
  unsigned long t4 = t2 * 60;
  SerPrnt("t1", t1); //результат 18
  SerPrnt("t2", t2); //результат 32
  SerPrnt("t3", t3); //результат -736 ?????? НУ КАК ТАК-ТО ????
  SerPrnt("t4", t4); //результат 1920 (=18*60)
}

void loop() {

}

 

Тип данных передаваемый в качестве второго аргумента функции SerPrnt стоит проверить.

Мало того что 16-битный , так ещё и знаковый.

pvakos
Offline
Зарегистрирован: 21.07.2019

ОГРОМНОЕ спасибо!

Слона-то я и не заметил!

Исправил на void SerPrnt(String S, unsigned long prmt) и все стало на место.

pvakos
Offline
Зарегистрирован: 21.07.2019

qwone пишет:

pvakos пишет:

Пожалуйста помогите! 

Как говорится, если человек идиот, то это надолго. И никто в этом не поможет.

Как говорится, если человек ХАМ, то это навсегда. 

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

pvakos пишет:

Как говорится, если человек ХАМ, то это навсегда. 

Хам или "Нехам" - это другое дело, но Квон тот же самый ответ написал тебе на полтора часа раньше. А "спасибо" не получил. ;))

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

pvakos пишет:

Как говорится, если человек ХАМ, то это навсегда. 

А если у кого-то с самоиронией проблемы, то это насколько?

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

pvakos пишет:

Надеюсь, что модератор удалит этот флуд не по теме.

Твой - да.