Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Деление на дробь на ассемблере
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Slavast
Столкнулся с математической проблемой. Необходимо полученное значение на АЦП поделить на 17.2, чтобы получить реальное входное напряжение.
Но не знаю как разделить число на ассемблере, да еще и на дробное.
Помогите с алгоритмом!
kovigor
Цитата(Slavast @ Dec 14 2010, 09:43) *
Помогите с алгоритмом!


А вы не делите на дробное. Помножьте числитель и знаменатель на 10 и делите на целое (у Атмела для АВР есть app.note: http://www.atmel.com/dyn/resources/prod_do...ts/doc0936.pdf). Или пишите на Си (и, опять же, не делите на дробное, если нет крайней необходимости). Если нужен именно алгоритм деления на дробное, то см., например, Я.К.Будинский "Логические цепи в цифровой технике". Там этот алгоритм подробно и с примерами расписан.
V_G
Если имеется в виду деление на константу, до делить ВООБЩЕ не надо! Вычислите число, обратное константе, умножьте его не степень двойки (лучше на 256 или 65536) и используйте умножение на константу с последующим отбрасыванием ненужных байтов
МП41
Цитата(Slavast @ Dec 14 2010, 07:43) *
Столкнулся с математической проблемой. Необходимо полученное значение на АЦП поделить на 17.2, чтобы получить реальное входное напряжение.

А как насчет более удобного опорного напряжения?
V_G
Цитата(МП41 @ Dec 14 2010, 16:45) *
А как насчет более удобного опорного напряжения?

Тож вариант: подкрутить опорное, чтобы делить не на 17.2, а на 16. Простой сдвиг вправо на 4 разряда. Но только если опорное можно регулировать
mempfis_
Цитата(Slavast @ Dec 14 2010, 09:43) *
Столкнулся с математической проблемой. Необходимо полученное значение на АЦП поделить на 17.2, чтобы получить реальное входное напряжение.
Но не знаю как разделить число на ассемблере, да еще и на дробное.
Помогите с алгоритмом!


Как подсказали перейдите от деления к умножению
Надо разделить на 17,2. Попытаемся представить это число в виде 65536/x
17,2 = 65536/x
x = 65536/17.2 = 3810
Теперь если взять любое входное значение, умножить на 3810 а потом отбросить два старших байта (что эквивалентно сдвигу на 16 вправо или делению на 65536) то получите то что Вам нужно. Не обзязательно брать 65536, можно любое число степень двойки (чем больше число тем выше точность). Суть метода в том чтобы уйти от операции деления к операции умножения с последующим сдвигом результата вправо. Умножение для любого процессора также как и сдвиг довольно простые и быстрые операции. Особенно если писать на ассемблере.
ae_
Цитата(mempfis_ @ Dec 14 2010, 17:45) *
Как подсказали перейдите от деления к умножению
Надо разделить на 17,2. Попытаемся представить это число в виде 65536/x
17,2 = 65536/x
x = 65536/17.2 = 3810
...умножить на 3810 а потом отбросить два старших байта...

отбросить два младших байта... получим целое число в диапазоне 0...59, это из входного диапазона АЦП 0...1023.
[telepat mode] предположу, что ТС нужно получить результат с дробной частью, типа 0...1023 -> 0...59.47 [/telepat mode]
=GM=
Если нужна дробная часть, то надо не отбрасывать два младших байта, а преобразовать их в десятичный вид и приписать к целой части.
mempfis_
Цитата(ae_ @ Dec 14 2010, 15:06) *
отбросить два младших байта... получим целое число в диапазоне 0...59, это из входного диапазона АЦП 0...1023.
[telepat mode] предположу, что ТС нужно получить результат с дробной частью, типа 0...1023 -> 0...59.47 [/telepat mode]


АААААА!!!!! Обшибся!!!!
Спасибо за поправку.
Нужно отбросить два младших байта а не старших!!! Точнее сдвинуть результат на 16 бит вправо!!!
Сам часто пользуюсь таким приёмом при работе с аналоговыми датчиками. Избавляет от исполдьзования громоздких П/П деления. IAR умный - сам понимает что при делении на 2**n оптимальным будет сдвиг а не div sm.gif
Sergey_Aleksandrovi4
Цитата(=GM= @ Dec 14 2010, 17:33) *
Если нужна дробная часть, то надо не отбрасывать два младших байта, а преобразовать их в десятичный вид и приписать к целой части.

Не уверен, что сработает такой подход. А вот домножив коэффициент на 10^k, где k требуемое число знаков после запятой

На примере, приведённом mempfis_
17,2 = 65536/x
x = 65536/17.2 = 3810
Для получения 3-х знаков после запятой
X = x * 1000 = 3810000

Теперь в цифрах, что получается. Например, число 12345
С помощью обычного деления
12345 / 17.2 = 717.7325581
С помощью умножения на коэффициент
12345 * X = 12345 * 3810000 = 47034450000 = 0xAF378C050
Отбрасываем 2 младших байта 0xAF378C050 >> 16 = 0xAF378 = 717688
Получили число 717688 три младших разряда которого в десятичном представлении есть разряды после запятой, т.е. 717.688
Погрешность получается 0.006%
_Pasha
Цитата(Sergey_Aleksandrovi4 @ Dec 15 2010, 12:24) *
Погрешность получается 0.006%

lol.gif Это погрешность округления 65536/17,2 = 3810,2325581395348837209302325581 посчитайте сами.
Все остальное (пока что) не влияет.
Slavast
Цитата(_Pasha @ Dec 15 2010, 12:07) *
lol.gif Это погрешность округления 65536/17,2 = 3810,2325581395348837209302325581 посчитайте сами.
Все остальное (пока что) не влияет.

предположу, что ТС нужно получить результат с дробной частью, типа 0...1023 -> 0...59.47


Даа, но не совсем.
Диапазон АЦП На ATMega 2561 - от 0...1023.
Диапазон Vвх - от 0..5V
На входе АЦП (туда я подаю 5V с питания)у меня стоит делитель напряжения на 3(Изначально так получилось, пришлось использовать). Т.о. там где-то 1.6 получается.
Но пока делитель не берем во внимание, т.к. будем оперировать с тем, что мы получаем и как нам отсюда получить значение в вольтах.
На терминале я получаю число 0x56h, или 86 в десятичной.
Соотношение между диапазоном АЦП(0..1023) и числом на экране (0..86) есть 1:12
Соотношение между напряжением (0..5V) и числом на экране (0..86) есть 1:17.2
Если я не ошибаюсь, то мне и нужен этот коэффициент 17.2, на который я делю число на терминале чтоб получить значение по шкале от 0..5.
ae_
Цитата(Slavast @ Dec 15 2010, 19:44) *
...Соотношение между напряжением (0..5V) и числом на экране (0..86) есть 1:17.2...

Код
;R16 = десятичное число 0...86
ldi R17, 71
mul R16, R17
lsr R1
lsr R1
;R1 = десятичное число 0...5

вот это надо было получить?
zombi
Цитата(Sergey_Aleksandrovi4 @ Dec 15 2010, 11:24) *
На примере, приведённом mempfis_
17,2 = 65536/x
x = 65536/17.2 = 3810
Для получения 3-х знаков после запятой
X = x * 1000 = 3810000


Мне кажется что умножать на 1000 нужно не округленное X а округлять до целого после умножения:
X = 65536/17.2*1000 = 3810233
Sergey_Aleksandrovi4
Цитата(zombi @ Dec 15 2010, 18:51) *
Мне кажется что умножать на 1000 нужно не округленное X а округлять до целого после умножения:
X = 65536/17.2*1000 = 3810233

Да, именно так. Спасибо за правку. _Pasha выше на это уже намекнул. Вот что значит пытаться включить голову во время обеда :-[
777777
Ёжики плакали, кололись, но продолжали писать на ассемблере плавающую точку...
Slavast
Цитата(777777 @ Dec 16 2010, 10:48) *
Ёжики плакали, кололись, но продолжали писать на ассемблере плавающую точку...


Ребят, кто знает: как можно преобразовать переменную с плавающей запятой (результат деления на коэффициент входного напряжения АЦП) в символьную константу (для вывода ее на терминал)на Си?
Есть какая-то функция или директива преобразования float в char?
Заранее, благодарим!
kovigor
Цитата(Slavast @ Dec 17 2010, 12:33) *
Ребят, кто знает: как можно преобразовать переменную с плавающей запятой (результат деления на коэффициент входного напряжения АЦП) в символьную константу (для вывода ее на терминал)на Си?
Есть какая-то функция или директива преобразования float в char?
Заранее, благодарим!


Есть такая функция:
ftoa
777777
Цитата(Slavast @ Dec 17 2010, 12:33) *
Ребят, кто знает: как можно преобразовать переменную с плавающей запятой (результат деления на коэффициент входного напряжения АЦП)

Деление на константу всегда можно заменить на умножение на величину ей обратную

Цитата(Slavast @ Dec 17 2010, 12:33) *
в символьную константу (для вывода ее на терминал)на Си?

Для этого есть алгоритмы преобразования двоичного в двоично-десятичное. Тут был товарищ который придумывал для этого хитроумные алгоритмы, в крайнем случае можно воспользоваться функцией itoa.
Slavast
Всем добрый день!
Уже 3-й день не могу перевести полученный результат с АЦП (деленный на коэффициент) с типа с плавающей запятой в символьный для вывода на UART терминала компьютера.
itoa - не подходит. Sprint не работает, тоже пробовал.
аещф- вообще не нашел такой функции.
Поделитесь опытом, может есть команда или процедура?
Спасибо откликнувшимся!
Diusha
Цитата(Slavast @ Dec 24 2010, 10:05) *
Поделитесь опытом, может есть команда или процедура?

Могу только поделиться опытом. Давно сделал и пользую не задумываясь набор подпрограмм с плавающей точкой для АВР на асм и свой "терминал" для компа на паскале, отображающий в зависимости от команды (полученной от АВР вместе с данными) данные как целые или "плавающие" или строку. Трудно представить, как раньше без этого работал и как все без этого работают.
Лучше немного (а может поначалу и много) попыхтеть, а дальше работать и наслаждаться
Slavast
Цитата(Diusha @ Dec 24 2010, 10:17) *
Могу только поделиться опытом. Давно сделал и пользую не задумываясь набор подпрограмм с плавающей точкой для АВР на асм и свой "терминал" для компа на паскале, отображающий в зависимости от команды (полученной от АВР вместе с данными) данные как целые или "плавающие" или строку. Трудно представить, как раньше без этого работал и как все без этого работают.
Лучше немного (а может поначалу и много) попыхтеть, а дальше работать и наслаждаться


Пишу на Си. Можете показать подпрограммы?
Tanya
Цитата(Slavast @ Dec 24 2010, 10:05) *
Всем добрый день!
Уже 3-й день не могу перевести полученный результат с АЦП (деленный на коэффициент) с типа с плавающей запятой в символьный для вывода на UART терминала компьютера.

А если Вам нужно только передать данные в компьютер, то зачем их преобразовывать? Гоните сырые в компьютер - пусть он тоже поработает.
Slavast
Цитата(Tanya @ Dec 24 2010, 13:04) *
А если Вам нужно только передать данные в компьютер, то зачем их преобразовывать? Гоните сырые в компьютер - пусть он тоже поработает.


И как по вашему я выведу число 4.467234 на UART? Это число то мне и надо в строку перевести!
rezident
Цитата(Slavast @ Dec 24 2010, 15:56) *
И как по вашему я выведу число 4.467234 на UART? Это число то мне и надо в строку перевести!
Число типа float занимает в памяти 4 байта. Передайте эти 4 байта в UART как есть, а в PC соберите их побайтно в такое же число float. Какие тут проблемы-то? laughing.gif
Tanya
Цитата(Slavast @ Dec 24 2010, 13:56) *
И как по вашему я выведу число 4.467234 на UART? Это число то мне и надо в строку перевести!

Ваш АЦП сразу Вам такое выдает?
sergeeff
Что-то мне сдается, что автор ветки не хочет советы слушать и с упорством, достойным лучшего применения, ломится в открытую дверь. Что вы уперлись в этот самый float? Чем вас не устраивают предложенные вам варианты?
ILYAUL
Цитата(sergeeff @ Dec 24 2010, 16:46) *
Что-то мне сдается, что автор ветки не хочет советы слушать и с упорством, достойным лучшего применения, ломится в открытую дверь. Что вы уперлись в этот самый float? Чем вас не устраивают предложенные вам варианты?

+1

Цитата
Как подсказали перейдите от деления к умножению
Надо разделить на 17,2. Попытаемся представить это число в виде 65536/x
17,2 = 65536/x
x = 65536/17.2 = 3810
Теперь если взять любое входное значение, умножить на 3810 а потом отбросить два старших байта (что эквивалентно сдвигу на 16 вправо или делению на 65536) то получите то что Вам нужно. Не обзязательно брать 65536, можно любое число степень двойки (чем больше число тем выше точность). Суть метода в том чтобы уйти от операции деления к операции умножения с последующим сдвигом результата вправо. Умножение для любого процессора также как и сдвиг довольно простые и быстрые операции. Особенно если писать на ассемблере

Уже всё рассказали , осталось только написать. Это элементарно и это asm
sergeeff
Чем две недели заси...ть себе и другим мозги, проще было бы переписать все на С и не плакаться в жилетку по поводу и без.
Diusha
Цитата(Slavast @ Dec 24 2010, 10:29) *
Можете показать подпрограммы?

Оп! Хотел выслать в личку, но не нашел, как там прикрутить файл. То ли там чего-то поменялось, то ли я забыл. Копаться лень, так что если объясните, как... Или оставьте мыло.

Как правильно подметила Tanya, АЦП выдает не float, а 2-байтовое число (10 бит). Можете его и отправлять, а уже на компе обсчитывать как угодно
andrewkrot
Есть такая книга - Гуртовцев, Гудыменко "Программы для микропроцессоров", 1989 года издания. Во времена 580ВМ80 у нас была бестселлером. Там и с плавающей точкой, и вообще без точек - вся арифметика на ассемблере расписана. Правда, AVR тогда еще наверное не было, по крайней мере никто об этом не знал. Рекомендую ознакомиться.
kovigor
Цитата(andrewkrot @ Dec 25 2010, 20:42) *
Есть такая книга - Гуртовцев, Гудыменко "Программы для микропроцессоров", 1989 года издания.


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