Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: как перемножать при помощи встроенного умножителя?
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > MSP430
cornflyer
мне нужно умножать два 16bit числа, потом результат поделить на 4095
галочка в ИАРе в опциях стоит - hardware multiplyer
но приведенный ниже код не работает!
может лучше на ассемблере сделать эту фунцкию?


unsigned int get_code ( unsigned int num_value, unsigned int k )
{
tmp = num_value * k ;
asm ("nop") ;
asm ("nop") ;
asm ("nop") ;
tmp = tmp >> 12 ;
return tmp ;
}
VAI
В том коде, который приведён, ничего работать не будет. tmp не объявлена.
Кстати, сдвиг на 12 эквивалентен делению на 4096, а не на 4095...
попробуйте так
Код
unsigned int get_code ( unsigned int num_value, unsigned int k )
{
unsigned long tmp;

tmp = num_value * k;
asm ("nop");
asm ("nop");
asm ("nop");
tmp = tmp >> 12;
return( unsigned int tmp );
}

// или короче
unsigned int get_code ( unsigned int num_value, unsigned int k )
{
return( (unsigned int)( num_value * k / (unsigned long)4095 ));
}
rezident
А зачем для столь простых операций целочисленного умножения и деления отдельную функцию городить? 07.gif Это же Си, а не ассемблер. Если в свойствах проекта указано о том, что нужно использовать аппаратный умножитель, то компилятор сам подставит вызов именно той функции, которая его использует.
cornflyer
я сделал так:

unsigned int dac_code = 0 ;
unsigned int HV_value = 0 ;
........

unsigned int get_code ( unsigned int num_value, unsigned int k )
{
unsigned long t = num_value * k ;
asm ( " nop " ) ;
asm ( " nop " ) ;
asm ( " nop " ) ;
asm ( " nop " ) ;
return ( t >> 12 ) ;
}

.........

HV_value = 500 ;

..........

// DAC8512 code = HV_value * 4000/5000 = HV_value * 3276/4095
dac_code = get_code ( HV_value, 3276 ) ;

.........

// отсылаю значение dac_code в ПК через RS-232
query_buf [ 6 ] = dac_code ;
query_buf [ 7 ] = dac_code >> 8 ;

В итоге на компе вижу цифру 15
Откуда!?
Должно быть 400.....

так железно должно работать:

unsigned int t = 0 ;

unsigned int get_code ( unsigned int num_value, unsigned int k )
{
stack1 [ 0 ] = num_value ;
stack1 [ 1 ] = num_value >> 8 ;
stack2 [ 0 ] = k ;
stack2 [ 1 ] = k >> 8 ;

result [ 3 ] = stack1 [ 1 ] * stack2 [ 1 ] ;
result [ 2 ] = stack1 [ 1 ] * stack2 [ 0 ] ;
result [ 1 ] = stack1 [ 0 ] * stack2 [ 1 ] ;
result [ 0 ] = stack1 [ 0 ] * stack2 [ 0 ] ;

t = ( result [ 3 ] << 16 ) + result [ 0 ] + ( ( result [ 2 ] + result [ 1 ] ) << 8 ) ;
return ( t >> 12 ) ;
}

но компилятор ругаеца - Warning[Pe063]: shift count is too large
что собственно естественно - у MSP430 размер регистров 16 бит
rezident
Вы опять наступаете на те же грабли. Без явного объявления (по-умолчанию) автоматическая переменная имеет тип int, для MSP430 int = 16 бит. Либо объявите переменные как unsigned long, либо делайте в каждом выражении явное приведение типа. Например,
Код
t =(unsigned int)((unsigned long)((unsigned long)(result[3])<<16UL)+(unsigned long)(result[0])+(unsigned long)((unsigned long)((unsigned long)(result[2])+(unsigned long)(result[1]))<<8UL));

Ну как, нравится? wink.gif Думаю, что нет. Так что определяйте типы переменных заранее и не вые надейтесь на "авось". Законы Мерфи-то работают! biggrin.gif
msalov
Всё таки непонятен смысл сдвига на 16 и таких сложных преобразований.
А как вы констатированли что функция умножения генерируемая компилятором не работает правильно?
AHTOXA
Цитата(cornflyer @ Feb 22 2008, 18:41) *
я сделал так:
unsigned int get_code ( unsigned int num_value, unsigned int k )
{
unsigned long t = num_value * k ;
asm ( " nop " ) ;
asm ( " nop " ) ;
asm ( " nop " ) ;
asm ( " nop " ) ;
return ( t >> 12 ) ;
}


А надо так:
Код
unsigned int get_code ( unsigned int num_value, unsigned int k )
{
  unsigned long t = num_value;
  t *= k;
  asm ( " nop " );
  asm ( " nop " );
  asm ( " nop " );
  asm ( " nop " );
  return ( t >> 12 );
}


Тогда будет всё в порядке. Кстати, без "nop"-ов тоже будет работать :-)
aag
Так вроде то же самое написано...

Попробую догадаться, почему так происходит:
В первом случае сначала происходит перемножение num_value и k и происходит переполнение, поэтому когда результат присваивается t, он ошибочный.
Во втором случае переменной t присваивается значение num_value и потом только происходит умножение t на k и при этом переполнения не возникает.
Так? smile.gif
AHTOXA
Цитата(aag @ Feb 24 2008, 10:58) *
В первом случае сначала происходит перемножение num_value и k и происходит переполнение, поэтому когда результат присваивается t, он ошибочный.


Да. В первом случае сначала перемножаются два int-а, результат тоже int.
Во втором случае - сначала присвоение long-у, потом умножение long-а на int, результат - long.

Можно также написать:
Код
unsigned long t = (unsigned long)num_value * k;
cornflyer
Код
unsigned int get_code ( unsigned int num_value, unsigned int k )
{
  unsigned long t = num_value;
  t *= k;
  return ( t >> 12 );
}


Так работает !!!!!!!!!!!! Ура !!!!!!!!!

P.S. Опять наступил на грабли приведения типов в С...
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.