Как бороться со счетчиком упаковки во встроенном С - PullRequest
12 голосов
/ 22 июня 2010

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

У меня есть функция, которая возвращает (timestamp + shifttime), и у меня есть другая функция, которая будет возвращать 1 или 0 в зависимости от того, истекло ли время, но может быть вероятность того, что мой счетчик обернется, как мне поступить с этим ?.

Спасибо

Большое спасибо за все ответы, ребята. Я дам более подробно в этом редактировании.

Я использую STM32 Cortex-M3. Я хочу использовать счетчик RTC, чтобы использовать его в качестве отметки для моего приложения для планирования задач, которые должны выполняться через определенные промежутки времени. RTC может генерировать прерывание переполнения, поэтому его не проблема обнаружить. основная проблема, с которой я сталкиваюсь (или, по крайней мере, считаю ее проблемой), заключается в том, что определенные задачи получают (метка времени + смещение), т. е.


int main( void )
{
FlashLedTimeStamp = ReturnCounter( 20 );  // currentcounter value + a shift of 20
StatusLedTimeStamp = ReturnCounter( 3 );  // currentcounter value + a shift of 3

//then later on ....
while(1)
{
    /* other tasks could go here */

    if( HasTimeElapsed( FlashLedTimeStamp );
    {
       /* do something and get another timestamp value */
       FlashLedTimeStamp = ReturnCounter( 20 );  // currentcounter value + a shift of 20
    }

    if( HasTimeElapsed( StatusLedTimeStamp );
    {
       /* do something and get another timestamp value */
       FlashLedTimeStamp = StatusLedTimeStamp( 3 );  // currentcounter value + a shift of 3
    }
}   
}

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

если мой текущий счетчик равен 250, когда я получаю свои метки времени, это означает, что FlashLedTimeStamp = 14 и StatusLedTimeStamp = 253, как мне проверить, что FlashLedTimeStamp истек ?? 1014 *

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

Ответы [ 11 ]

20 голосов
/ 23 июня 2010

Это не будет иметь значения до тех пор, пока разница между начальным и конечным счетчиком будет меньше (2 ^ 32) / 2, и предполагается, что выполняется 32-битная арифметика дополнения до 2 (почти всегда верно), даже если значение счетчика охватываетнаматывается точку.Например:

Start count: 0xfffffff
End Count:   0x00000002 (incremented through 0,1,2 - i.e. three counts)

End - Start == 0x00000002 - 0xfffffff == 0x00000003

Таким образом, правильный ответ достигается при условии, что счетчик представляет собой битовую ширину встроенного целочисленного типа и этот тип используется.Если, возможно, регистр счетчика не является шириной встроенного целочисленного типа, вы можете достичь того же эффекта, маскируя биты «переполнения» более высокого порядка.

Если вам нужен больший счет по другим причинам или еслиразница между последовательными временными метками слишком велика, тогда вы можете просто использовать другое целое число, которое увеличивается, когда счетчик младшего разряда оборачивается.Это целое число будет формировать старшие биты большего целого числа, поэтому младший бит второго целого числа является 33-м битом этого большего целого числа.

13 голосов
/ 22 июня 2010

Если вы берете две отметки времени и ваше первое чтение на больше , чем второе, то ваш счетчик обернут.Это основной способ обнаружения счетчика оберток.

Однако он не обнаружит, был ли счетчик обернут несколько раз, или случай, когда счетчик обернут и оказывается больше первого чтения,Поскольку вы сказали, что это встроенная система, и ваше описание заставляет ваш «счетчик» звучать как часы, посмотрите, можете ли вы установить прерывание на срабатывание всякий раз, когда часы достигают нуля (так что вы будете получать прерывание каждый раз при сбросе часов).Когда это прерывание срабатывает, увеличьте значение отдельного счетчика.Это должно эффективно повысить точность ваших часов и позволить обернуть счетчик, не вызывая проблем.

4 голосов
/ 23 июня 2010

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

if (current_time - expiry_time < 0x80000000UL)
    /* timer has expired */

Предполагается, что вы проверяете срок действия по крайней мере один раз каждые 0x80000000 тиков и что ваш самый длинный таймер настроен на истечение менее 0x80000000 тиков в будущем.

2 голосов
/ 23 июня 2010

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

uint32_t timer( void);             // Returns the current time value
uint32_t timeout;

timeout = timer() + offset;

// wait until timer() reaches or exceeds timeout value
while ((int32_t)(timeout - timer()) > 0);
2 голосов
/ 22 июня 2010

Вопрос немного расплывчатый. Одна возможность - установить флаг, когда вы впервые заметите, что время истекло. Безошибочным способом было бы добавить второй счетчик, который увеличивается при переполнении первого счетчика. Это фактически создаст 64-битный счетчик, который не будет переполнен.

1 голос
/ 23 июня 2010

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

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

Если вы хотите найти промежуток времени между двумя событиями, скажем, начало и конец

start = таймер чтения lasttime = start rollover = 0

во время ожидания события

nowtime = таймер чтения, если (nowtime> lasttime) ролловер + = 1 (это обратный счетчик) lasttime = nowtime

событие происходит: end = таймер чтения

общее время = начало - конец (это обратный счетчик и обратите внимание, что эта математика работает даже при переворачивании)

общее время = общее время / коэффициент масштабирования для перехода от тиков к секундам, минутамнезависимо от общего времени + = ролловер * секунд / минут / независимо от значения 2 ^ 32

, если у вас есть счетчик увеличения, тогда время

Если вы можете гарантировать, что ваше событие произойдет в течение 2 ^ 32, счетчик васне нужносделайте ролловер сейчас в последний раз, когда вам нужно только начать и закончить, и общее количество тиков = начало - конец будет работать, даже если счетчик переходит от 0x00000000 до 0xFFFFFFFF между началом и концом.

1 голос
/ 22 июня 2010

Одна из возможностей - привести обе переменные к 64-битной длине, а затем выполнить суммирование.После этого сравните с максимальным 32-битным значением, чтобы определить, упакован ли он.

1 голос
/ 22 июня 2010

Самый простой способ сделать это - создать «счетчик эпох», который явно подсчитывает переходы.(Пример: у вас есть аппаратный счетчик, который считает секунды 0..59. Ваш счетчик эпох будет считать минуты, увеличивая его каждый раз, когда он заметил, что счетчик секунд перевернулся.)

Ваша функция future_scheduler затем читаеттекущую эпоху и время, а также вычисляет новую эпоху и время для вашего события.

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

0 голосов
/ 23 июня 2010

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

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

0 голосов
/ 22 июня 2010

Поскольку вы встроены, у вас может быть доступ к биту переполнения ЦП. Это будет установлено, когда добавление переполняет его регистр. Полезно для добавления цепочки AddCarry.

...