реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> как перемножать при помощи встроенного умножителя?
cornflyer
сообщение Feb 22 2008, 10:10
Сообщение #1


Частый гость
**

Группа: Свой
Сообщений: 166
Регистрация: 11-07-06
Из: Dubna
Пользователь №: 18 729



мне нужно умножать два 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 ;
}
Go to the top of the page
 
+Quote Post
VAI
сообщение Feb 22 2008, 10:34
Сообщение #2


Профессионал
*****

Группа: Модераторы
Сообщений: 1 120
Регистрация: 17-06-04
Пользователь №: 37



В том коде, который приведён, ничего работать не будет. 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 ));
}


--------------------
Если зайца бить, его можно и спички научить зажигать
Сколько дурака не бей - умнее не будет. Зато опытнее
Go to the top of the page
 
+Quote Post
rezident
сообщение Feb 22 2008, 11:39
Сообщение #3


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



А зачем для столь простых операций целочисленного умножения и деления отдельную функцию городить? 07.gif Это же Си, а не ассемблер. Если в свойствах проекта указано о том, что нужно использовать аппаратный умножитель, то компилятор сам подставит вызов именно той функции, которая его использует.
Go to the top of the page
 
+Quote Post
cornflyer
сообщение Feb 22 2008, 13:41
Сообщение #4


Частый гость
**

Группа: Свой
Сообщений: 166
Регистрация: 11-07-06
Из: Dubna
Пользователь №: 18 729



я сделал так:

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 бит
Go to the top of the page
 
+Quote Post
rezident
сообщение Feb 22 2008, 14:17
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Вы опять наступаете на те же грабли. Без явного объявления (по-умолчанию) автоматическая переменная имеет тип 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
Go to the top of the page
 
+Quote Post
msalov
сообщение Feb 22 2008, 14:21
Сообщение #6


Знающий
****

Группа: Свой
Сообщений: 526
Регистрация: 24-08-07
Из: Беларусь, Минск
Пользователь №: 30 045



Всё таки непонятен смысл сдвига на 16 и таких сложных преобразований.
А как вы констатированли что функция умножения генерируемая компилятором не работает правильно?
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Feb 22 2008, 17:09
Сообщение #7


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(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"-ов тоже будет работать :-)


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
aag
сообщение Feb 24 2008, 05:58
Сообщение #8


Частый гость
**

Группа: Свой
Сообщений: 81
Регистрация: 8-04-06
Из: Новосибирск
Пользователь №: 15 939



Так вроде то же самое написано...

Попробую догадаться, почему так происходит:
В первом случае сначала происходит перемножение num_value и k и происходит переполнение, поэтому когда результат присваивается t, он ошибочный.
Во втором случае переменной t присваивается значение num_value и потом только происходит умножение t на k и при этом переполнения не возникает.
Так? smile.gif
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Feb 24 2008, 15:44
Сообщение #9


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



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


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

Можно также написать:
Код
unsigned long t = (unsigned long)num_value * k;


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
cornflyer
сообщение Feb 26 2008, 06:51
Сообщение #10


Частый гость
**

Группа: Свой
Сообщений: 166
Регистрация: 11-07-06
Из: Dubna
Пользователь №: 18 729



Код
unsigned int get_code ( unsigned int num_value, unsigned int k )
{
  unsigned long t = num_value;
  t *= k;
  return ( t >> 12 );
}


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

P.S. Опять наступил на грабли приведения типов в С...
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 28th July 2025 - 19:51
Рейтинг@Mail.ru


Страница сгенерированна за 0.01444 секунд с 7
ELECTRONIX ©2004-2016