Как иметь дело с переносящимся счетчиком во встроенном C

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

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

Спасибо

Большое спасибо за всех парней ответов. Я предоставлю больше подробную информацию в этом редактировании.

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


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 истек??

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

12
задан jramirez 23 June 2010 в 22:06
поделиться

11 ответов

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

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

13
ответ дан 2 December 2019 в 03:22
поделиться

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

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

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

4
ответ дан 2 December 2019 в 03:22
поделиться

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

1
ответ дан 2 December 2019 в 03:22
поделиться

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

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
ответ дан 2 December 2019 в 03:22
поделиться

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

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

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

start = read timer последнее время = начало rollover = 0

в ожидании того, что произойдет

nowtime = read timer if(nowtime>lasttime) rollover+=1 (это понижающий счетчик) lasttime = nowtime

событие произошло: end = считать таймер

total time = start - end (это счетчик вниз, и заметьте, что эта математика работает даже при перевороте)

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

если у вас есть счетчик вверх, то nowtime

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

1
ответ дан 2 December 2019 в 03:22
поделиться

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

0
ответ дан 2 December 2019 в 03:22
поделиться

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

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

0
ответ дан 2 December 2019 в 03:22
поделиться

Это не будет иметь значения до тех пор, пока разница между начальным и конечным отсчетом меньше (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

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

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

21
ответ дан 2 December 2019 в 03:22
поделиться

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

2
ответ дан 2 December 2019 в 03:22
поделиться

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

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

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

1
ответ дан 2 December 2019 в 03:22
поделиться

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

if (timestamp + shifftime < timestamp) 
    it_wrapped();
0
ответ дан 2 December 2019 в 03:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: