LINUX.ORG.RU

[AVR][Assembler]перевод в десятичный формат

 ,


0

1

суть задачи, взять данные из АЦП, перевести в нормальный вид и отправить в UART
нормальный вид это значение в десятичном формате для вывода в UART
опорное напряжение 5 вольт, АЦП 10-битное, то есть падает число от 0 до 1023
как я уже сделал: делим 5/1024, получается примерно 0,00488
дальше 488 умножаем на полученное значение
число лежит в пределах от 000488 до 499712
первый разряд это целое, остальные цифры это дробная часть
499712 это в памяти контроллера как 0111 1010 0000 0000 0000
а дальше встаёт проблема перевода в десятичный вид
пока то, до чего сам допер
завести шесть регистров под искомое число
дальше, сдвигать каждый регистр (командой ROR)(1 байт, микроконтроллер 8-битный) в котором лежит двоичное значение (всего получается 3 регистра)
в зависимости от того вылазиет единица или ноль в Cary флаге складывать с 1, 2, 4, 8, 16, 32, 64 ...
складывать надо по разрядам, при сложении надо проверять чтоб в каждом разряде не было числа больше 10 и переносить бит в следующий разряд, если требуется

проблема такого метода, что под конец придётся складывать достаточно большие числа, порядка пару сотен тысяч, последовательность где то надо хранить в десятичном виде по разрядам
как упрощение, можно использовать только один регистр АЦП, то есть первые 8 разрядов
получится 5/256 примерно 0,0195
дальше 195 * (макс значение АЦП, 256) = 49920
на один разряд меньше + это число влазиет в 2 регистра
очевидно, падает точность измерений, в общем, это не критично

вопрос, есть ли более быстрый и компактный алгоритм для решения такой задачи? что думаете? как можно еще решить?
по сути пытаюсь сделать из МК вольтметр, большая точность (все равно даже с погрешностью получается намного точнее обычного вольтметра) и время выполнения не важны, однако хочется красивого и быстрого алгоритма, именно на асме

Ответ на: комментарий от Norgat

да, на Си это было бы в пару строк
но я это делаю в целях обучения, в частности изучения архитектуры АВР, поэтому начал с асма
в данный момент даже более интересно найти алгоритм, который бы решал задачу, чем конечный результат
сейчас написал на Си простую программу расчета вещественных чисел, с каждой операцией прошивка пухнет как дрожжах
походу математика на АВРах непросто реализуется, так как регистры 8-битные, блока FPU нету, делить не умеет
умеет правда умножать, и то, это только меги, тини порой и умножать не умеют
эх жаль, интересно как в бытовых калькуляторах реализованы математические операции, там вроде даже не МК, а просто непрограммируемая логика

Fatalist
() автор топика
Ответ на: комментарий от Fatalist

Посмотри исходник printf из какой-нибудь компактной libc для данной архитектуры.

PolarFox ★★★★★
()
Ответ на: комментарий от Fatalist

да, на Си это было бы в пару строк

Ну вот сделай на Си. А потом бери полученный асм листинг и чисть его пока не будет выглядеть так, как ты хочешь :)

Norgat ★★★★★
()

берешь исходное число, делишь его в цикле на 10, пока результат деления не станет 0, остаток от каждой операции деления пишешь в выходной буфер

типа так

while(ADC_val)
{
dec_buf[i++]=ADC_val/10;
dec_buf/=10;
}

а т.к. AVR делить не умеет, придется реализовать деление самому :)

Harald ★★★★★
()

itoa(*buf, val, base); На асме ты задолбаешься, ибо скорее всего твой МК делить не умеет.

Artificial_Thought ★★★★
()

от 0 до 1023 ... делим 5/1024

а может делим на 1023? Если не понял, нарисуй 14 (типа 1024) рисок от 0 до 13 (типа 1023) и посчитай количество делений — промежутков между двумя соседними отметками/рисками. Их 13, а не 14. А АЦП указывает именно на промежуток между уровнями.

Цена деления прибора - 5.000 подели на количество делений шкалы, рисок 1024, делений 1023.

Разницы на самом деле почти нет, но такие глупые ошибки нельзя допускать, проектируя измерительный прибор.

Во-вторых, небольшой ликбез по метрологии и смысле хранения кучи знаков после запятой: цена деления 5.0/1023=0.0048875..., а погрешность в измерениях следует считать половиной цены деления, далее по правилам пишем снятое+-погрешность, выносим за скобки множитель у снятого и погрешности, так чтоб у снятого остался один знак перед запятой, у погрешности затем отбрасываем (!) все цифры кроме двух значащих, а затем округляем (!) до одной значащей цифры, следом тело результата округляем до того же количества знаков после запятой, что и погрешность.

Пример, получил ты 16: 16*5/1023+-5.0/(1023*2)=0.078201+-0.00244379

Вынесем 10 в минус второй за скобки

(7.8201+-0.244379)*10^-2

У погрешности отбросили 4379, округлили 0.24 до 0.2 по правилам, теперь 7.8201 округляем до одной после запятой, как и в 0.2 — 7.8

(7.8+-0.2)*10^-2

Смысл всего этого ликбеза в том, чтоб убедить тебя, что 10-битный АЦП отдавая тебе число, совсем не гарантирует точность до трёх знаков после запятой, которую ты получишь, поделив 5 на 1023 на калькуляторе. В реальности истинный результат лежит где-то между 7.33 и 7.82 на 10^-2 или где-то так, потому что компаратор АЦП не сработал на уровне 15 (15*5/1023=7.33*10^-2), а сработал на уровне 16 (16*5/1023=7.82*10^-2), значит результат в этом диапазоне. И +-0.002 это объективная точность для такого АЦП. Так что смысла в 8 из 000488 и 2 в 499712 мало. И вопрос не в том, как ты это выведешь, а в том, отражает ли то что ты собрался считать в шестизначных числах истинный результат измерений с той точностью, которую ты собрался выделить.

Так что, если ты всё-таки хочешь считать в МК и беря за основу деление в 488 (или 489), можешь делать как придумал, только учти, что из рассчитанных в МК скажем 499712, верных знаков только 3 старших.

И в-последних, кто тебе запрещает передавать по уарту номер отсчёта от 0 до 1023, а обрабатывать уже на другом конце уарта? :)

anonymous
()
Ответ на: комментарий от TERRANZ

конечно, есть еще всякие микропаскали с бейсиками. только вот в 99,9% даташитов приводят примеры кода либо на си, либо на ассемблере.

ymn ★★★★★
()
Ответ на: комментарий от ymn

для AVR'ок де-факто есть только ассемблер и си.

http://winavr.sourceforge.net/

WinAVRTM (pronounced «whenever») is a suite of executable, open source software development tools for the Atmel AVR series of RISC microprocessors hosted on the Windows platform. It includes the GNU GCC compiler for C and C++.

Всё ещё думаешь, что под них нету C++ ?

Norgat ★★★★★
()
Ответ на: комментарий от Norgat

а я и не говорил что под AVR нет компиляторов Си++. Просто микроконтроллеры AVR - они разные) Под какую-нибудь ATtiny13 пишут на ассемблере из-за того, что в 1k памяти на Си много не затолкаешь.

Сейчас на работе пишем для Atmega128 на Си и ассемблере и памяти не хватает(

ymn ★★★★★
()

> то есть падает число от 0 до 1023

сгенерить на персоналке массив 1024 готовых значений уже предлагали?

arsi ★★★★★
()

платиновые треды школьников о мк
один из самых частых вопросов, тащемта (можно было гуглом обойтись)

anonymous
()
Ответ на: комментарий от Norgat

меня на дикий смех пробивала идея программировать на С++ для tiny12, у которого оперативной памяти нет ;) Со всеми шаблонами, наследованием, виртуальными функциями и прочими наворотами

Harald ★★★★★
()
Ответ на: комментарий от Harald

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

опять кого то в гугле забанили http://www.avr-asm-tutorial.net/avr_en/calc/CONVERSION.html


спасибо за ссылку, гуглил конечно, но что то неудачно

И в-последних, кто тебе запрещает передавать по уарту номер отсчёта от 0 до 1023, а обрабатывать уже на другом конце уарта? :)


хочется универсальности, подключился через терминал, вбил команду, получил значение
и да, спасибо за подробное объяснение, с погрешностью да, она там будет еще больше, потому что не учитывается погрешность самого АЦП, но мне большая точность не нужна, до второго знака после запятой хватит более чем

сгенерить на персоналке массив 1024 готовых значений уже предлагали?


нет :)

Fatalist
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.