Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Определение промежутка времени
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > MSP430
d7d1cd
Привет всем. Делаю программу на ассемблере. Есть дата и время 2-х событий, которые хранятся в двоично-десятичном коде. Второе событие всегда происходит позже первого. Необходимо определить сколько времени прошло между этими событиями.
Psych
А таймером никак??
d7d1cd
Таймером? Каким образом? Мне же не отмерить промежуток времени надо, а определить его.
AlexFTF
А в чем проблема? От второго события отнять первое...
d7d1cd
Цитата(AlexFTF @ Apr 23 2013, 08:40) *
А в чем проблема? От второго события отнять первое...

В этом и проблема. Как это сделать? Подскажите алгоритм...
decom
Вы задаете вопросы, на которые настолько легко найти ответ в гугле и интернете, что возникают вопросы...
http://habrahabr.ru/post/112630/
d7d1cd
Цитата(decom @ Apr 23 2013, 13:01) *
Вы задаете вопросы, на которые настолько легко найти ответ в гугле и интернете, что возникают вопросы...
http://habrahabr.ru/post/112630/

Спасибо за ссылку на статью. Однако это не совсем то, что мне нужно.Точнее это совсем не то, что мне нужно. Мне не надо отмерять промежуток времени. Мне надо определить сколько прошло между 2-мя событиями секунд, минут, часов и суток.
rezident
Цитата(d7d1cd @ Apr 23 2013, 14:25) *
Мне надо определить сколько прошло между 2-мя событиями секунд, минут, часов и суток.

Вообще-то вычисление времени проходят в первом полугодии третьего класса начальной школы sm.gif
Это вовсе не бином Ньютона - переводите обе даты в нименьшие единицы измерения (секунды) и вычитаете одно число из другого. По больщому счету такие вычисления ничем не отличаются от функции измерения интервала времени "в попугаях", реализованной на таймере, о котором вам ранее намекали.
d7d1cd
Цитата(rezident @ Apr 23 2013, 14:17) *
Вообще-то вычисление времени проходят в первом полугодии третьего класса начальной школы sm.gif
Это вовсе не бином Ньютона - переводите обе даты в нименьшие единицы измерения (секунды) и вычитаете одно число из другого. По больщому счету такие вычисления ничем не отличаются от функции измерения интервала времени "в попугаях", реализованной на таймере, о котором вам ранее намекали.

На счет преобразования в наименьшую единицу измерения я полностью согласен. Однако осмелюсь повториться, что я пишу на ассемблере, поэтому ищу максимально простой алгоритм.

На счет преобразования: перевести в секунды минуты, часы и дни легко. Но как быть с месяцами и годами? Ведь в них не постоянное число секунд...


adnega
Цитата(rezident @ Apr 23 2013, 14:17) *
...переводите обе даты в нименьшие единицы измерения (секунды) и вычитаете одно число из другого.

Например, так:
CODE


Начало эпохи 01.01.2000 00:00:00
Работает корректно до 2100 года.

//-----------------------------------------------------------------------------
//! \fn extern DWORD date_to_int(DWORD y, DWORD m, DWORD d)
//! \brief Преобразует дату в число.
//! \param y Год.
//! \param m Месяц.
//! \param d День месяца.
//! \return Номер дня по порядку от начала эпохи.
//! \sa int_to_date().
//-----------------------------------------------------------------------------
extern DWORD date_to_int(DWORD y, DWORD m, DWORD d);

//-----------------------------------------------------------------------------
//! \fn extern void int_to_date (const DWORD jd, DWORD *y, DWORD *m, DWORD *d)
//! \brief Преобразует число в дату.
//! \param jd Номер дня по порядку от начала эпохи.
//! \param y Указатель на переменную для года.
//! \param m Указатель на переменную для месяца.
//! \param d Указатель на переменную для дня месяца.
//! \sa date_to_int().
//-----------------------------------------------------------------------------
extern void int_to_date (const DWORD jd, DWORD *y, DWORD *m, DWORD *d);

//-----------------------------------------------------------------------------
// int date_to_int(int y, int m, int d)
//-----------------------------------------------------------------------------
DWORD date_to_int(DWORD y, DWORD m, DWORD d)
{
if(m < 3)
{
m += 12;
y -= 1;
}
return ((y * 1461) >> 2) + ((m * 306 + 7) / 10) + d - 730533;
}

//-----------------------------------------------------------------------------
// void int_to_date(DWORD jd, int *y, int *m, int *d)
//-----------------------------------------------------------------------------
void int_to_date(DWORD jd, DWORD *y, DWORD *m, DWORD *d)
{
int aa, bb, cc, dd, ee, mm, xx;

aa = jd + 2483589;
bb = (aa * 4 + 3) / 146097;
cc = aa - ((146097 * bb) >> 2);
dd = (4 * cc + 3) / 1461;
ee = cc - ((1461 * dd) >> 2);
mm = ((5 * ee + 2) * 13707) >> 21;

*d = ee - ((16043274 * mm + 209716) >> 19) + 1;
*m = mm + 3 - 12 * ((mm * 27) >> 8);
*y = 100 * bb + dd - 4800 + ((mm * 27) >> 8);
}
d7d1cd
Спасибо за код. Можно попросить прокомментировать строки функции, которая преобразует дату в число дней...
decom
В коде похоже ошибка, надо бы проверить.
AlexFTF
Цитата(d7d1cd @ Apr 23 2013, 17:49) *
Однако осмелюсь повториться, что я пишу на ассемблере, поэтому ищу максимально простой алгоритм.


Позвольте поинтересоваться почему Вы пишите программу на ассемблере, а не на Си? Ведь на Си гораздо проще и быстрее реализовать поставленную задачу...
d7d1cd
Цитата(AlexFTF @ Apr 24 2013, 08:15) *
Позвольте поинтересоваться почему Вы пишите программу на ассемблере, а не на Си? Ведь на Си гораздо проще и быстрее реализовать поставленную задачу...


Я понимаю, что на С все проще. Однако я могу писать только на ассемблере. Причину такого выбора сказать не могу, так как это будет противоречить правилам данного форума.




Kopa
Цитата(d7d1cd @ Apr 24 2013, 16:07) *
Я понимаю, что на С все проще. Однако я могу писать только на ассемблере. Причину такого выбора сказать не могу, так как это будет противоречить правилам данного форума.

Какому пункту правил?

P.S. Я, например, пишу на Форт (Forth) и подозреваю что тоже нарушаю какой то пункт правил данного форума. rolleyes.gif (на Си кстати тоже, как и на асм)
А судя по репликам прозвучащим в топике не относящихся к вопросу как задающего так и отвечающего то правила нарушают многиеsm.gif
а модераторы форума стоят рядышком и наблюдают за "засиранием" форума "непонятными" вопросами и "непонятными" ответами и "непонятно" где
они должны быть озвучены, а может сразу перейти ссылкой на FAQ или его допонить? smile3046.gif
adnega
Цитата(d7d1cd @ Apr 23 2013, 15:57) *
Спасибо за код. Можно попросить прокомментировать строки функции, которая преобразует дату в число дней...

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

Цитата(decom @ Apr 23 2013, 16:51) *
В коде похоже ошибка, надо бы проверить.

Перевод туда и обратно проверял числительно для всех дат от 2000 до 2099 года.
Можете показать проблемное место?
d7d1cd
Цитата(Kopa @ Apr 28 2013, 09:51) *
Какому пункту правил?


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


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

msalov
Такой наивный вопрос: а чем стандартная библиотека Си не угодила? Там есть функция работы со временем mktime, которая время в человеко-приемлемой форме переводит во время Unix (количество секунд с 01.01.1970 00:00:00). Ну а дальше разницу взять - дело тривиальное.
d7d1cd
Цитата(msalov @ May 1 2013, 00:05) *
Такой наивный вопрос: а чем стандартная библиотека Си не угодила? Там есть функция работы со временем mktime, которая время в человеко-приемлемой форме переводит во время Unix (количество секунд с 01.01.1970 00:00:00). Ну а дальше разницу взять - дело тривиальное.

Такое наивное сто двадцать пятое объяснение: Я ПИШУ НА АССЕМБЛЕРЕ!!!


msalov
Пишите хоть в машинных кодах.
Из моего сообщения вы могли бы почерпнуть, если бы не торопились с выводами, такие варианты:
* использовать библиотеку напрямую (если только у вас не орден велосипедостроителя 3ей степени), ведь из ПИСАНИЯ НА АССЕМБЛЕРЕ не следует невозможность использования библиотек;
* использовать исходный код (реализаций на Си предостаточно) что б реализовать алгоритм своими силами;
* бинарник нужной функции из библиотеки пропустить через дизассемблер, ручками выправить полученное до ассемблируемого вида, ведь вам же нужен АССЕМБЛЕР.
Stanislav
Цитата(d7d1cd @ May 1 2013, 09:35) *
Такое наивное сто двадцать пятое объяснение: Я ПИШУ НА АССЕМБЛЕРЕ!!!
Извините, но при чём здесь Ассемблер?
Изучите основы систем счисления, а потом пишите хоть на суахили...
jack_avenger
Цитата(Stanislav @ May 2 2013, 09:57) *
Извините, но при чём здесь Ассемблер?
Изучите основы систем счисления, а потом пишите хоть на суахили...

Сложно будет человеку на Ассемблере писать функции деления не на константу. Если быстродействие не кусается, то можно преобразование выполнять через отнимание в цикле сначала количества секунд в годе (с учетом высокосных), потом месяцы (например через масив количества секунд в месяце), сутки и т.д.
adnega
Цитата(jack_avenger @ May 3 2013, 23:06) *
Сложно будет человеку на Ассемблере писать функции деления не на константу.

Если человек использует ассемблер, то эта функция у него уже есть.
jack_avenger
Цитата(adnega @ May 3 2013, 22:10) *
Если человек использует ассемблер, то эта функция у него уже есть.

Не факт. Я даже в программе на С стараюсь избегать деления на что-либо отличное от степени двойки.
adnega
Цитата(jack_avenger @ May 3 2013, 23:13) *
Не факт. Я даже в программе на С стараюсь избегать деления на что-либо отличное от степени двойки.

А как же вывод десятичных чисел на дисплей? Деление на константу 10.
В свое время делал на АСМе получается (частное и остаток) компактно и быстро, но с использованием команды умножения.
Функцию деления произвольно числа на произвольное число делал для кр1878ве1, МК51, AVR.
Заниматься вычитаниями можно, но зачем, когда можно взять и один раз написать нужную функцию?
jack_avenger
Цитата(adnega @ May 3 2013, 22:24) *
А как же вывод десятичных чисел на дисплей? Деление на константу 10.

Использование деления на 10 для вывода на дисплей это немного "из пушки по воробьям".
У некоторых МSP (например у СС430) есть преобразователь BIN->BCD, и BCD->BIN. Обычно эти регистры сидят в адресном пространстве ЖКИ.
Если преобразователя нет, надо преобраз]овывать используя команду двоично-десятичного сложения dadd.x. Так в разы быстрее деления.
В С она доступна через __bcd_add_long().
Вот пример из книги "MSP430 Microcontroller Basics"
Код
; Assembly routine to convert 16-bit unsigned binary value to BCD
; Taken from Application Reports , section 5.5.3
; Called from C as: uint32_t UIntToBCD (uint16_t UIntValue );
; 16-bit parameter "UIntValue" passed in R12
; 32-bit value "UIntToBCD" returned in R13:R12
; Uses only the scratch registers R12 -R15 so no stacking necessary
;-----------------------------------------------------------------------
        PUBLIC  UIntToBCD                ; Export symbol outside this file
        RSEG    CODE                     ; Essential as usual
UIntToBCD:                               ; Name of function as usual
        mov.w   R12 ,R14                 ; Move input and leave R12 free for result
        clr.w      R12                   ; Clear registers for result
        clr.w      R13
        mov.w   #0x0010 ,R15             ; Initialize loop counter to number of bits
LoopStart:
        rla.w      R14                   ; Shift msb of input into carry bit
        dadd.w   R12 ,R12                ; R13:R12 = 2* R13:R12 + carry bit DECIMALLY
        dadd.w   R13 ,R13                ; lsword then msword
        dec.w     R15                    ; Decrement loop counter
        jnz         LoopStart            ; Repeat if nonzero
        reta                             ;  Return instruction in MSP430X
       ; ret                             ; Usual MSP430 return instruction
END
d7d1cd
Господа, деление меня не волнует (так же как и умножение). Для своих целей я уже написал функции для деления и умножения. Причем они работают с 32-х разрядными числами.
Если не трудно, то покажите алгоритм определения разности между датами в минутах (точнее не нужно).
decom
Вы уже достали своими детскими вопросами.
Вот алгоритм определения разности в минутах ВНУТРИ ОДНОГО ГОДА.
Дата А: 12.34 21/01/2013
Дата Ю: 17.35 05/05/2013

Определяем количество полных дней в каждой дате с начала года:
Дата А: январь 21 = 21
Дата Б: январь 31, февраль 28, март 31, апрель 30, май 5= 125

Определяем количество полных часов с начала даты
Дата А: 12
Дата Б: 17

Определяем количество минут с начала нового часа
Дата А:34
Дата Б:35

Уже известно что в сутках 24 часа или 1440 минут
А в одном часе 60 минут

Переводим в минуты:
Дата А дни 21*1440 = 30240, часы 12*60=720, минуты 34
Дата Б дни 125*1440 = 180000, часы 17*60=1020, минуты 35

Складываем минуты для каждой даты
Дата А: 30240+720+34=30994
Дата Б: 180000+1020+35=181055

Вычисляем разность между датами в минутах:
Разность: ДатаБ-ДатаА = 181055-30994=150061

Ответ: разность в минутах равна 150061 (сто пятьдесят тысяч шестьдесят одна минута)
Чтобы получить ответ в секундах надо умножить число на 60.
Ответ в секундах: 150061*60=9003660 (девять миллионов три тысячи шестьсот шестьдесят секунд)




adnega
Цитата(decom @ May 4 2013, 11:01) *
Вы уже достали своими детскими вопросами.
Вот алгоритм определения разности в минутах ВНУТРИ ОДНОГО ГОДА.
Дата А: 12.34 21/01/2013
Дата Б: 17.35 05/05/2013
...
Ответ в секундах: 150061*60=9 003 660 (девять миллионов три тысячи шестьсот шестьдесят секунд)

А вот для произвольной даты внутри столетия (2000 - 2099 года)

Для первой даты: поскольку месяц меньше 3, то у года вычитаем единицу, а месяц увеличиваем на 12.
((2013 - 1) * 1461) / 4 + ((1 + 12) * 306 + 7) / 10 + 21 - 730533 =
734883 + 398 + 21 - 730533 = 4769
В секундах: ((4769 * 24 + 12) * 60 + 34) * 60 + 0 = 412 086 840

Для второй даты:
(2013 * 1461) / 4 + (5 * 306 + 7) / 10 + 5 - 730533 =
735248 + 153 + 5 - 730533 = 4873
В секундах: ((4873 * 24 + 17) * 60 + 35) * 60 + 0 = 421 090 500

Разница: 9 003 660

decom
Полагаю ТС собирается сделать гаджет типа "сколько секунд я прожил. Поэтому ему надо с 1900 года.
Слесарь
Помнится, вопрос расчета времени по календарю не такой и простой как в приведенных формулах, помнится даже CTime от микрософт не всегда качественно справлялся с этой задачей. Если вопрос принципиален могу покапаться в архивах и привести парочку вариантов возникновения ошибки в реальных приложениях где производится расчет промежутка времени.

вот например

Код
CDate::CDate(const SYSTEMTIME &st)
{
    /* Так как бывает летнее и зимнее время, возьмем
        за базу полдень. Что бы перевод времени не влиял
        на дату. То есть, если за базу берется полночь
        переход на летнее время после зимнего может произвести
        при вычислении BackDay() пропуск целой даты.
    */
    CTime t( st.wYear, st.wMonth, st.wDay, 12, 0, 0 );

    m_time = t;
}
adnega
Цитата(Слесарь @ May 4 2013, 21:07) *
Помнится, вопрос расчета времени по календарю не такой и простой как в приведенных формулах

Возможно, но для 2000 - 2099 годов работает для любой даты. Проверял перебором.
Слесарь
странно, разве вам известно как распределится время в промежутке 2014 ... 2099 годах? Время ведь понятие человеческое, людям свойственно менять отношение к собственным понятиям. Вспомните Мюнхаузена с его 32 числом, ведь это нововведение вполне может быть легализовано в один прекрасный момент, как собственно недавняя приписка чуть более десятка дней к календарю.
haker_fox
QUOTE (Слесарь @ May 5 2013, 02:31) *
странно, разве вам известно как распределится время в промежутке 2014 ... 2099 годах? Время ведь понятие человеческое, людям свойственно менять отношение к собственным понятиям. Вспомните Мюнхаузена с его 32 числом, ведь это нововведение вполне может быть легализовано в один прекрасный момент, как собственно недавняя приписка чуть более десятка дней к календарю.

При переводе даты в количество секунд (минут) нужно учитывать високосные годы. Как, написано много где. Вроде все. Количество дней в месяцах кроме февраля - фиксированное.
Слесарь
Рас читывать количество месяцев за промежуток времени по секундам, достаточно сомнительное занятие. Учитывать только секунды при расчете даты, это прямолинейное ориентирование только на один ориентир Солнце. Ошибка в расчете количества месяцев присутствует постоянно.
Кста есть значимые свидетельства ошибок таких расчетов, например католическая Пасха рассчитывается по григорианскому солнечному календарю (учитывается только солнечный год, календарь прямолинейный, как по секундам), католики часто нарушают правило праздновать Пасху в первое воскресенье после наступления полнолуния, которое выпадает на период после весеннего равноденствия. После празднования иудейской Пасхи, если случается совпадение, то правила предписывают перейти к полнолунию следующего месяца.
В настоящее время католическая пасха часто празднуется раньше иудейской, что строго запрещается церковными канонами.
adnega
Цитата(Слесарь @ May 4 2013, 21:31) *
Время ведь понятие человеческое, людям свойственно менять отношение к собственным понятиям.

Все просто: приведенные формулы годятся для существующего сейчас календаря.
Когда календарь поменяют, тогда поменяем и формулы.
Привязываться к астрономической точности в рамках решаемой задачи явный перебор.
Эдак можно задачу и не решить... ведь в сутках не ровно 24 часа... да и вращается Земля вокруг
собственной оси с небольшим снижением оборотов...
А если два события происходят в разных точках пространства... или по разные стороны "линии перемены дат"...
Условностей много, и это еще без привлечения религий))
d7d1cd
Сразу хочу сказать спасибо всем за помощь. Алгоритм приведенный adnega вполне подходит. Только объясните мне, почему если месяц меньше 3-х, то необходимо год уменьшить на 1, а количество месяцев увеличить на 12?
adnega
Цитата(d7d1cd @ May 6 2013, 18:29) *
Только объясните мне, почему если месяц меньше 3-х, то необходимо год уменьшить на 1, а количество месяцев увеличить на 12?

Видимо, чтобы "изменчивый" февраль был в конце.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.