Вычитание двух переменных uint32_t дает вид переполненного результата? - PullRequest
2 голосов
/ 13 июня 2019

Я программирую stm8s микроконтроллер и использую STVD IDE и COSMIC компилятор.

Результат вычитания двух uint32_t переменных сохраняется в другой uint32_t переменная.Иногда странный результат возникает в результате этого процесса.Это странное значение всегда является ожидаемым значением, причем самые значимые биты установлены в 1s.

Вот фрагмент моего кода:

static uint32_t lastReceivedLed = 0;
uint32_t timeSinceLast = 0;

timeSinceLast = IL_TimTimeNow() - lastReceivedLed;

if(timeSinceLast > 2500U)
{
      Inhibitor = ACTIVE;  // HERE IS MY BREAKPOINT
}

Вот как IL_TimTimeNow()определены:

volatile uint32_t IL_TimNow = 0;

uint32_t IL_TimTimeNow(void)
{
    return IL_TimNow; // Incremented in timer ISR
}

Вот некоторые реальные значения из сеанса отладки:

enter image description here

timeSinceLast должно быть 865280 - 865055 = 225 = 0xE1

Однако вычисленный компилятором результат равен 4294967265 = 0xFFFFFFE1

Обратите внимание, что младший значащий байт является правильным, в то время как остальные байты установлены в 1s в результате компилятора !!

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

Это переполнение?Что может вызвать эту ситуацию?

1 Ответ

7 голосов
/ 13 июня 2019

Значения, отображаемые в отладчике:

  • IL_TimNow = 865280
  • lastReceivedLed = 865055
  • timeSinceLast = 4294967265

Обратите внимание, что 4294967265 - это то, что вы получаете, когда конвертируете -31 в uint32_t.Это говорит о том, что значение IL_TimNow, возвращаемое IL_TimTimeNow() непосредственно перед вычитанием, на самом деле было lastReceivedLed - 31, что составляет 865055 - 31, что составляет 865024.

Показана разница между значением IL_TimNowв отладчике (865280), а значение IL_TimNow непосредственно перед вычитанием (865024) равно 256. Кроме того, все младшие 8 битов обоих значений равны нулю.Это говорит о том, что значение считывалось так же, как младший байт округлялся до 0, а следующий байт увеличивался.В комментарии в IL_TimTimeNow() написано // Incremented in timer ISR.Поскольку 8-разрядный микроконтроллер может считывать только один байт за раз, кажется, что таймер ISR произошел, когда функция считывала четыре байта IL_TimNow.

Существует два способа решенияпроблема.Первый способ - отключить прерывание таймера в IL_TimTimeNow(), пока читается значение IL_TimNow.Таким образом, функция IL_TimTimeNow() может быть изменена на что-то вроде этого:

uint32_t IL_TimTimeNow(void)
{
    uint32_t curTime;

    disable_timer_interrupt();
    curTime = IL_TimNow;
    enable_timer_interrupt();
    return curTime;
}

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

Другой способ решения проблемы - продолжать читать IL_TimNow в IL_TimTimeNow(), пока не получите два одинаковых значения.Таким образом, функция IL_TimTimeNow() может быть изменена на что-то вроде этого:

uint32_t IL_TimTimeNow(void)
{
    uint32_t prevTime, curTime;

    curTime = IL_TimNow;
    do
    {
         prevTime = curTime;
         curTime = IL_TimNow;
    } while (curTime != prevTime);
    return curTime;
}

Обычно будет одна итерация цикла do ... while, читая IL_TimNow дважды.Время от времени будет две итерации цикла, читая IL_TimNow три раза.На практике я не ожидал бы более двух итераций цикла, но функция может справиться и с этим.

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

uint32_t IL_TimTimeNow(void)
{
    uint32_t curTime;

    curTime = IL_TimNow;
    if ((curTime & 0xFF) == 0)
    {
        // Least significant byte possibly just wrapped to 0
        // so remaining bytes may be stale. Read it again to be sure.
        curTime = IL_TimNow;
    }
    return curTime;
}

Если производительность не является проблемой, используйте одну из более безопасных версий.

...