Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Как в Си определить выход за пределы кода (переполнение) результата операции ?
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > MCS51, AVR, PIC, STM8, 8bit
MaxiMuz
Элементарная ситуация: Имеется два 16-битных числа , при их сложении нужно отслеживать ситуацию переполнения результата.
Пробую:
Код
uint16_t temp16;
uint16_t sumADC;

if ((sumADC+=temp16)>0xffff)
     { // Отключение АЦП  !!
         ADCSRA=(1<<ADEN);}

понимаю что это нет то ....
Нужно как можно короче превести это к коду (для AVR):
Код
add rd_l,rs_l
adc rd_h,rs_h
brcs m1
....

Как это все оформляется в Си ?
arttab
а по флагу переполнения не проще ли?
maksimp
Такой именно ассемблерный код как вы хотите может быть и не получится.
Варианты:
Код
unit16_t x=sumADC;
sumADC+=temp16;
if (x>0xffffU-temp16)

Код
unit16_t x=sumADC;
sumADC+=temp16;
if (((unit32_t)x+temp16)>0xffffUL)

Код
unit32_t x=sumADC+temp16;
sumADC=(unit16_t)x;
if (x>0xffffUL)
VslavX
Можно попробовать так:
Код
uint16_t temp16;
uint16_t sumADC;

sumADC+=temp16;
if (sumADC < temp16)
{
     { // Отключение АЦП  !!

Но ассемблерного варианта скорее всего тоже не получится.
Alexey K
CODE

uint16_t temp16;
uint16_t sumADC;
uint32_t sum32;

sum32 = sum32 + temp16;

if ( sum32 <= 0xFFFFFFFF )
{
sumADC = (uint16_t) sum32;
}
else
{
//overflow actions
}
Vetal-Soft
Код
if ((0xffff-sumADC) < temp16)
      {  . . .
ViKo
А что, arttab дал плохой совет? Доступ к флагам имеется?
ARV
Цитата(Alexey K @ Apr 24 2013, 09:54) *
CODE

uint16_t temp16;
uint16_t sumADC;
uint32_t sum32;

sum32 = sum32 + temp16;

if ( sum32 <= 0xFFFFFFFF )
{
sumADC = (uint16_t) sum32;
}
else
{
//overflow actions
}
ну, все-таки скорее всего чуть-чуть иначе:
CODE

uint16_t temp16;
uint16_t sumADC;
uint32_t sum32;

sum32 = sum32 + temp16;

if ( sum32 <= 0xFFFF ) // переполнение-то для 16-бит надо отслеживать
{
sumADC = sum32;
}
else
{
//overflow actions
}
Alexey K
Согласен. Утро однакоsm.gif
MrYuran
А при сравнении флаг С учитывается?
Иначе крайние варианты не катят

Тьфу, пардон, uint32 же..
demiurg_spb
Цитата(ARV @ Apr 24 2013, 09:59) *
Код
uint32_t sum32;
В avr-gcc 4.7.x имеется тип __uint24

Цитата(ViKo @ Apr 24 2013, 09:58) *
А что, arttab дал плохой совет? Доступ к флагам имеется?

Имеется. Просто обращение к SREG по маске
Код
if (SREG & (1<<n)) {...}

Лучше всю эту красоту завернуть в макрос типа:
Код
#define add16_sat(a,b) \
do \
{ \
   (a) += (b); \
   if (SREG & (1<<SREG_C)) \
   { \
      (a) = -1U; \
   } \
} while (0)
MaxiMuz
Цитата(maksimp @ Apr 24 2013, 06:09) *
Такой именно ассемблерный код как вы хотите может быть и не получится.
Варианты:
Код
unit16_t x=sumADC;
sumADC+=temp16;
if (x>0xffffU-temp16)

Код
unit16_t x=sumADC;
sumADC+=temp16;
if (((unit32_t)x+temp16)>0xffffUL)

Код
unit32_t x=sumADC+temp16;
sumADC=(unit16_t)x;
if (x>0xffffUL)

введение дополнительных переменных , тем более 32 бита как предлагают Alexey K и ARV не приемлемо, тажкж на счету каждый такт. Т.к. процедура выполняется в прерывании и времяни на выполнение оч.мало

Цитата(arttab @ Apr 24 2013, 04:06) *
а по флагу переполнения не проще ли?

похоже что это самый лаконичный способ!

Код
    if (SREG & (1<<SREG_C))
  80:    0f b6           in    r0, 0x3f; 63
  82:    00 fe           sbrs    r0, 0
  84:    04 c0           rjmp    .+8      ; 0x8e <__vector_9+0x48>

конечно не "brcc m1" ...
maksimp
Цитата(MaxiMuz @ Apr 25 2013, 14:05) *
введение дополнительных переменных , тем более 32 бита как предлагают Alexey K и ARV не приемлемо, тажкж на счету каждый такт. Т.к. процедура выполняется в прерывании и времяни на выполнение оч.мало

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

Цитата(MaxiMuz @ Apr 25 2013, 14:05) *
похоже что это самый лаконичный способ!
Код
    if (SREG & (1<<SREG_C))

Он не гаранитированно даёт результат. У вас этот фрагмент кода сейчас такой:
Код
uint16_t temp16;
uint16_t sumADC;
sumADC+=temp16;
if (SREG & (1<<SREG_C))

Допустим что есть ещё некоторые переменные, с которыми до того или после того производятся действия, и фрагмент большего размера может быть например что-то вроде:
Код
uint16_t x,y;
...
x+=y;
...
uint16_t temp16;
uint16_t sumADC;
sumADC+=temp16;
if (SREG & (1<<SREG_C))

Компилятор имеет право переставить действия, и иногда он этим правом пользуется, и может получиться в ассемблере уже что-то будто компилированное с такого текста:
Код
uint16_t x,y;
...
...
uint16_t temp16;
uint16_t sumADC;
sumADC+=temp16;
x+=y;
if (SREG & (1<<SREG_C))

и результат будет неверным.
MaxiMuz
Цитата(maksimp @ Apr 25 2013, 21:09) *
Проверьте что в ассемблере получится. Может быть соптимизируется и нормально будет, дополнительные переменные могут быть выкинуты компилятором.

Он не гаранитированно даёт результат. У вас этот фрагмент кода сейчас такой:
Код
uint16_t temp16;
uint16_t sumADC;
sumADC+=temp16;
if (SREG & (1<<SREG_C))

Допустим что есть ещё некоторые переменные, с которыми до того или после того производятся действия, и фрагмент большего размера может быть например что-то вроде:
Код
uint16_t x,y;
...
x+=y;
...
uint16_t temp16;
uint16_t sumADC;
sumADC+=temp16;
if (SREG & (1<<SREG_C))

Компилятор имеет право переставить действия, и иногда он этим правом пользуется, и может получиться в ассемблере уже что-то будто компилированное с такого текста:
Код
uint16_t x,y;
...
...
uint16_t temp16;
uint16_t sumADC;
sumADC+=temp16;
x+=y;
if (SREG & (1<<SREG_C))

и результат будет неверным.

я уже пробывал как говорили Они , компил.вводит доп.регистры и код в любом случае получается большой.
А по поводу перестановки действий, вполне возможно ожидать от такого компилятора всяких "пакостей" , поэтому я каждый раз заглдядываю в ассемблерный листинг программы
XVR
Сделайте ассемблерную inline функцию. GCC это очень хорошо умеет
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.