реклама на сайте
подробности

 
 
4 страниц V   1 2 3 > »   
Reply to this topicStart new topic
> Программный таймер, как красиво обойти переполнение?
Леонид Иванович
сообщение Jan 24 2014, 09:53
Сообщение #1


Местный
***

Группа: Участник
Сообщений: 318
Регистрация: 21-07-06
Из: Минск
Пользователь №: 18 986



Есть прерывание с периодом 1 мс, где инкрементируется 32-разрядный счетчик:

Код
void SysTick_Handler(void)
{
  TSysTimer::Counter++;
}


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

Код
void TSoftTimer::Start(uint32_t t)
{
  FinalCount = TSysTimer::Counter + t;
}


Истек ли интервал, проверяется так:

Код
bool TSoftTimer::Over(void)
{
  return(TSysTimer::Counter >= FinalCount);
}


Всё хорошо, но примерно через 50 дней счетчик TSysTimer::Counter переполнится и всё сломается. Как красиво это обойти? При этом можно наложить ограничение, что формируемый интервал никогда не превышает половины (или даже четверти) периода счетчика, а проверка переполнения тоже делается часто, много раз за период счетчика.


--------------------
Go to the top of the page
 
+Quote Post
ViKo
сообщение Jan 24 2014, 10:21
Сообщение #2


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Нужно не сравнивать числа, а вычитать. Тогда отрицательная разность из-за ограничения разрядности превратится в положительную.
Go to the top of the page
 
+Quote Post
scifi
сообщение Jan 24 2014, 10:49
Сообщение #3


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(ViKo @ Jan 24 2014, 14:21) *
Нужно не сравнивать числа, а вычитать. Тогда отрицательная разность из-за ограничения разрядности превратится в положительную.

+1. Кстати, стандарт Си гарантирует, что при вычитании (unsigned int) - (unsigned int) результат будет корректным, пока разница во времени не превышает те самые 50 дней (для 32 бит), несмотря на переполнение первой или второй переменной.
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Jan 24 2014, 11:16
Сообщение #4


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(ViKo @ Jan 24 2014, 14:21) *
+1 Всегда так делаю.


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
RabidRabbit
сообщение Jan 24 2014, 11:21
Сообщение #5


Местный
***

Группа: Свой
Сообщений: 397
Регистрация: 3-12-09
Из: Россия, Москва
Пользователь №: 54 040



не знаю, как на ARM, а для x64 вычитание не прокатывает (gcc 4.7.2):
CODE
int gggg( uint32_t a1, uint32_t a2 )
{
40076c: 55 push %rbp
40076d: 48 89 e5 mov %rsp,%rbp
400770: 89 7d fc mov %edi,-0x4(%rbp)
400773: 89 75 f8 mov %esi,-0x8(%rbp)
return (a2 - a1) <= 0;
400776: 8b 45 f8 mov -0x8(%rbp),%eax
400779: 3b 45 fc cmp -0x4(%rbp),%eax
40077c: 0f 94 c0 sete %al
40077f: 0f b6 c0 movzbl %al,%eax
}
400782: 5d pop %rbp
400783: c3 retq

Go to the top of the page
 
+Quote Post
scifi
сообщение Jan 24 2014, 12:17
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(RabidRabbit @ Jan 24 2014, 15:21) *
не знаю, как на ARM, а для x64 вычитание не прокатывает (gcc 4.7.2):

Вы невнимательно читали. Типы должны быть unsigned int.
А в вашем примере перед вычитанием значения приводятся к типу int (он же int64_t) со всеми вытекающими...
Go to the top of the page
 
+Quote Post
Леонид Иванович
сообщение Jan 24 2014, 12:24
Сообщение #7


Местный
***

Группа: Участник
Сообщений: 318
Регистрация: 21-07-06
Из: Минск
Пользователь №: 18 986



О, спасибо, точно! А я было зациклился на сравнениях и чуть не погряз в условиях.

Код
TSoftTimer::TSoftTimer(uint32_t t = 0)
{
  Interval = t;
}

void TSoftTimer::Start(uint32_t t)
{
  Interval = t;
  StartCount = TSysTimer::Counter;
}

void TSoftTimer::Start()
{
  StartCount = TSysTimer::Counter;
}

void TSoftTimer::SetInterval(uint32_t t)
{
  Interval = t;
}

bool TSoftTimer::Over(void)
{
  return(TSysTimer::Counter - StartCount >= Interval);
}


--------------------
Go to the top of the page
 
+Quote Post
Tarbal
сообщение Jan 24 2014, 12:59
Сообщение #8


Профессионал
*****

Группа: Свой
Сообщений: 1 351
Регистрация: 21-05-10
Пользователь №: 57 439



Цитата(ViKo @ Jan 24 2014, 13:21) *
Нужно не сравнивать числа, а вычитать. Тогда отрицательная разность из-за ограничения разрядности превратится в положительную.


Важное замечание:
Вычитать нужно беззнаковые величины иначе результат будет неверный.


О! scifi уже написал sm.gif

Сообщение отредактировал Tarbal - Jan 24 2014, 12:59
Go to the top of the page
 
+Quote Post
Genadi Zawidowsk...
сообщение Jan 24 2014, 13:21
Сообщение #9


Профессионал
*****

Группа: Участник
Сообщений: 1 620
Регистрация: 22-06-07
Из: Санкт-Петербург, Россия
Пользователь №: 28 634



а в NT x86 таймер 64 бита... и процедура получения значения для сравнения не используется ничего похожего на запрещение прерываний. Вам такое ней подойдёт? кроме того, можно ещё получить точный часов с "некруглой" частотой прерываний.
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Jan 24 2014, 13:49
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



А я вечно горожу проверку что типа если текущее меньше начального, то сложить хвост и начала... вот я балдаsm.gif)))

хотя последний раз я дошел до того что просто в таймере сделал
if(Delay >0)
Delay --;

и если надо выждать 10 тиков, то
Delay = 10; и проверяю что он не 0....

у вас все равно переменная Start задействована, так чего ей значение хранить, когда она может просто считаться назад?
Go to the top of the page
 
+Quote Post
ViKo
сообщение Jan 24 2014, 14:03
Сообщение #11


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(Tarbal @ Jan 24 2014, 15:59) *
Важное замечание:
Вычитать нужно беззнаковые величины иначе результат будет неверный.

Возможно, и для знаковых будет все нормально.
Go to the top of the page
 
+Quote Post
scifi
сообщение Jan 24 2014, 14:28
Сообщение #12


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(ViKo @ Jan 24 2014, 18:03) *
Возможно, и для знаковых будет все нормально.

Да, возможно. Но это может зависеть от процессора и/или компилятора. А для типа unsigned int это гарантируется стандартом языка Си.
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Jan 24 2014, 16:50
Сообщение #13


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



для без знакового все просто, пусть 8 бит

250 - старт

0 - 250 == -250 = 0x06 (остальные биты улетают из за переполнения) == 6.
то есть 0 - 250 == 256 - 250 = 6

а если знаковое, то переполнение на 127.
и после 127 идет -128
120 - старт
-128 - 120 == -248 == 8 как должно было бы быть.

Все по битам верно, думаете компилятор может вмешаться?
Go to the top of the page
 
+Quote Post
mantech
сообщение Jan 24 2014, 17:50
Сообщение #14


Гуру
******

Группа: Участник
Сообщений: 2 219
Регистрация: 16-08-12
Из: Киров
Пользователь №: 73 143



Цитата(Genadi Zawidowski @ Jan 24 2014, 17:21) *
а в NT x86 таймер 64 бита... и процедура получения значения для сравнения не используется


Дак 64 бита никогда не переполнятся за всю жизнь biggrin.gif
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Jan 24 2014, 18:48
Сообщение #15


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



Цитата(mantech @ Jan 24 2014, 21:50) *
Дак 64 бита никогда не переполнятся за всю жизнь biggrin.gif

да ну бросьте.
это всего навсего
584 942.41735507203247082699137494 года
ничто по сравнению с жизнью вселенной...

если тик микросекунда..., а если пико?
Go to the top of the page
 
+Quote Post

4 страниц V   1 2 3 > » 
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th June 2025 - 17:49
Рейтинг@Mail.ru


Страница сгенерированна за 0.01484 секунд с 7
ELECTRONIX ©2004-2016