Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Преобразвание bin-hex
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Kuznec9999
Проблема следующая. После оцифровки сигнала в АЦП, в регистре имеется 8бит данных. Задача преобразовать этот двоичный регистр в три, к которые будут отображаться на трёх семисегментных индикаторах соответственно. В индикаторах должен отображаться десятичный эквивалент сигнала (0-255). Подскажите, легко ли это реализовать на ассемблере, и где про это можно почитать? Спасибо.
rezident
Ключевое слово для поиска по форуму - BCD. Вот в теме про исходники вроде что-то было. http://electronix.ru/forum/index.php?showtopic=10934
А я как-то вот такой алгоритм (правда на Си) предлагал http://caxapa.ru/116486.html
Kuznec9999
Цитата(rezident @ Apr 30 2008, 02:59) *
Ключевое слово для поиска по форуму - BCD. Вот в теме про исходники вроде что-то было. http://electronix.ru/forum/index.php?showtopic=10934
А я как-то вот такой алгоритм (правда на Си) предлагал http://caxapa.ru/116486.html


Спасибо. Жаль, что все исходники в основном на Си. А мне хотелось бы разобраться в алгоритме этого преобразования. Скажите, а что такое BCD? Так называется данное преобразование?
Сергей Борщ
Цитата(Kuznec9999 @ Apr 30 2008, 02:03) *
Жаль, что все исходники в основном на Си. А мне хотелось бы разобраться в алгоритме этого преобразования.
Вы меня, конечно, извините, но исходник на С это и есть алгоритм, записанный практически чистейшим английским языком.
Цитата(Kuznec9999 @ Apr 30 2008, 02:03) *
Скажите, а что такое BCD? Так называется данное преобразование?
В таких случаях обычно сначало спрашивают гугля.
rezident
Цитата(Kuznec9999 @ Apr 30 2008, 05:03) *
Спасибо. Жаль, что все исходники в основном на Си. А мне хотелось бы разобраться в алгоритме этого преобразования.
Дык алгоритм может быть реализован на любом языке программирования. А алгоритм реализованный на ЯВУ проще понять, чем асм-овый ИМХО.
Цитата(Kuznec9999 @ Apr 30 2008, 05:03) *
Скажите, а что такое BCD? Так называется данное преобразование?
Binary-coded decimal из Википедии.
domowoj
Есть много методов преобр.
Самый быстрый - табличный(если не жалко памяти),
самый медленный - вычитаешь из bin 1 - прибавляешь 1 к 3-х байтному числу, анализируя достижение
каждого байта числа 10, если 10 - сбрасываешь его и прибавляешь 1 к след. байту, и т.д.
Есть оптимальные алгоритмы в букварях http://lord-n.narod.ru/walla.html
поищи, не помню где именно.
777777
Цитата(Kuznec9999 @ Apr 30 2008, 03:03) *
Спасибо. Жаль, что все исходники в основном на Си. А мне хотелось бы разобраться в алгоритме этого преобразования.


Алгоритм этого преобразования описан у Титце-Шенка на стр. 321-322 (в инете можно найти если у тебя нет). Правда, реализовать его на С проблематично - он изобилует сдвигами и проверками переноса из 3-го разряда в 4-й.

Цитата(rezident @ Apr 30 2008, 02:59) *
А я как-то вот такой алгоритм (правда на Си) предлагал http://caxapa.ru/116486.html


Боюсь что ваш алгоритм не самый эффективный.

А вообще-то все уже написано до нас: в аппнотах в avr204.asm
MrYuran
Цитата(domowoj @ Apr 30 2008, 04:33) *
Есть много методов преобр.
Самый быстрый - табличный(если не жалко памяти),
самый медленный - вычитаешь из bin 1 - прибавляешь 1 к 3-х байтному числу, анализируя достижение
каждого байта числа 10, если 10 - сбрасываешь его и прибавляешь 1 к след. байту, и т.д.

cranky.gif 01.gif
итого 255 итераций для преобразования числа 255?
01.gif 01.gif 01.gif
а просто поделить на 10 никак?

Я бы сделал так:
Код
char number;
char digit1=0; // 1 цифра
char digit2=0; // 1 цифра
char digit3=0; // 1 цифра
...
number=...     //

...
if(number>=200)
{
  digit1=2;
  number-=200;
}
else

  if(number>=100)
  {
    digit1=1;
    number-=100;
  }
digit2=number/10;
digit3=number-digit2*10;

не претендую на оптимальность , но сам так делаю
777777
Цитата(MrYuran @ Apr 30 2008, 09:24) *
не претендую на оптимальность , но сам так делаю

Да уж... Господа, читайте классику, она вечна. smile.gif И программа в avr24.asm основана именно на алгоритме, описанном у Титце-Шенка (см. выше).
TarasH
Смотри сюда http://www.atmel.ru/Articles/Atmel13.htm
777777
Цитата(TarasH @ Apr 30 2008, 10:26) *


Цитата
В данной статье рассматривается программа "bin16bcd5" (см. Приложение, Программа 1), написанная Терешкиным А. В. согласно алгоритму, изложенному в [1], и выполняющая ту же задачу.
Последняя программа по быстродействию, длине кода и количеству используемых регистров оказалась более эффективной, чем первая.


Че-то я не представляю как она могла оказаться быстрее, если в ней требуется выполнить до 10 вычитаний на каждую цифру, т.е. всего 50, плюс кучу проверок, а в avr204.asm коротенький цикл выполняется лишь 16 раз.
blackfin
Ещё пару ссылок:

int >> str
itoa на asm, из темы "51 vs AVR"...

Тема возникает с завидной регулярностью.. smile.gif
ReAl
Цитата(777777 @ Apr 30 2008, 09:40) *
Че-то я не представляю как она могла оказаться быстрее, если в ней требуется выполнить до 10 вычитаний на каждую цифру, т.е. всего 50, плюс кучу проверок, а в avr204.asm коротенький цикл выполняется лишь 16 раз.

Ну так сравнить код и всё!
В avr204.asm цикл для bin2BCD16 не такой и коротенький.
Внутри 16 проходов цикла сдвига делается ещё десятичная коррекция, команды для которой у AVR нет. Это у 51-го можно коррекцию делать во время сдвига, выходит аккуратно и быстро.
Коррекция там сама сделана как цикл по байтам результата, итого это три прохода.
Это, конечно, быстрее, чем делением на 10, но в целом отвратительная реализация, попытка перенести на архитектуру AVR решение, которое на неё плохо ложится.
Во внутреннем цикле два вычитания, итого уже 16*3*2 = 96 гарантированных вычитаний.
Ещё там максимум четыре косвенных обращения к регистрам как к памяти через указатель Z, которые вместе эквивалентны четырём словным вычитаниям. Ещё эквивалент максимум 16*3*4 = 192 вычитания.
Итого 288 макс.

И Вы говорите, что 50 _максимум_ это много?
Ну и их там не 50. Для последней цифры единички вычитать не нужно вообще, для предпоследней вычитания байтовые, а не словные, для первой будет вычитаться максимум 7 раз. Ну там ещё компенсационные сложения для восстановления числа, итого там "лень считать, но в переводе на словные вычитания точно не больше 40".
Итого: avr204.asm
Код
;* Number of words    :25
;* Number of cycles    :751/768 (Min/Max)
;* Low registers used    :3 (tBCD0,tBCD1,tBCD2)
;* High registers used  :4(fbinL,fbinH,cnt16a,tmp16a)    
;* Pointers used    :Z

25 слов, 9 регистров, больше 750 тактов.

Метод вычитания с atmel.ru
Код
;* Количество слов кода            :25 + возврат
;* Количество циклов               :25/176 (Мин/Макс) + возврат
;* Использованные младшие регистры :нет
;* Использованные старшие регистры :4(fbinL,fbinH/tBCD0,tBCD1,tBCD2)
;* Использованные указатели        :нет

Столько же слов, в два раза меньше регистров, минимум в четыре раза быстрее.
MrYuran
Цитата
Это, конечно, быстрее, чем делением на 10

А что вас так смущает деление на 10?
В пределах байта это 4 сдвига и 4 сложения
Равно как и умножение
Kuznec9999
Попробовал avr204.asm, а именно bin2bcd8... На выходе числа не соответствуют входу (контроллер mega8)
ReAl
Цитата(MrYuran @ Apr 30 2008, 11:49) *
А что вас так смущает деление на 10?
В пределах байта это 4 сдвига и 4 сложения
Равно как и умножение
Ну, тут плавно перешли к полуоффтопикув виде сравнения преобразования 16-битного числа в avr204.asm и на сайте atmel.ru. Там "деление" на 10 несколько подлиннее будет. Хотя с учётом наличия команд умножения у мег и для 16 бит "деление" на 10 по скорости гораздо выгоднее, чем avr204.asm, а в одном из вариантов выгоднее и чем вычитания, но длиннее по коду.
Ну а avr204.asm для 16 бит соревнуется по тормознутости с именно делением на число, в качестве которого в процедуру передаётся 10.

Кстати, для вывода как правило удобнее иметь сразу распакованный BCD или ASCII, это тоже можно сделать вычитаниями, там получается приблизительно те же числа (26 слов, от 32 до 183 циклов в зависимости от числа, исходник, кажется, от =AVR=, пробегал по форуму на телесисемамах лет 5 назад).
Если слегка модифицировать алгоритм - убрать восстановление остатка после циклов вычитаний и циклы через один сделать циклами сложения, то это будет ещё короче при приблизительно тех же временах, только минимум будет не для 0, а для 9090..9099, а максимум не для 59999, а для 60900..60909.
Код
;Converts unsigned integer value of bin_h:bin_l to ASCII or unpacked BCD
;Only upper registers can be used, bin_h/asc4 and bin_l/asc5
;variable pairs must share common register each.
;21 words, max/min cycles with rcall/ret: 183(60900..60909)/27(9090..9099)
;No other registers used;)
;  ascii/unpacked BCD in "reversed" order - leftmost digit stored in r20, rightmost one - in r16

; use for BIN to ASCII
.set ZERO='0'
.set NINE='9'

; use for BIN to unpacked BCD
;.set ZERO=0
;.set NINE=9

.def    asc1    =r20
.def    asc2    =r19
.def    asc3    =r18
;
.def    asc4    =r17
.def    bin_h    =r17
;
.def    asc5    =r16
.def    bin_l    =r16
;

itoa:
    ldi    asc1,ZERO-1;Will be '0' after 1st increment
sub10k:
    inc    asc1;'0','1','2','3','4','5','6'
    subi    bin_l,low(10000)
    sbci    bin_h,high(10000)
    brsh    sub10k
;
    ldi    asc2,NINE+1
add1k:
    dec    asc2;'9','8','7','6','5','4','3','2','1','0'
    subi    bin_l,low(-1000)
    sbci    bin_h,high(-1000)
    brlo    add1k
;
    ldi    asc3,ZERO-1
sub100:
    inc    asc3;'0','1','2','3','4','5','6','7','8','9'
    subi    bin_l,low(100)
    sbci    bin_h,high(100)
    brsh    sub100
;
    ldi    asc4,NINE+1;Re-use bin_h as ASC4
add10:
    dec    asc4;'9','8','7','6','5','4','3','2','1','0'
    subi    bin_l,-10;Re-use bin_l as ASC5
    brlo    add10
    subi    asc5,-(ZERO);convert to ASCII
;
    ret
singlskv
Цитата(Kuznec9999 @ Apr 30 2008, 02:42) *
После оцифровки сигнала в АЦП, в регистре имеется 8бит данных. Задача преобразовать этот двоичный регистр в три,

Ну вот, такое отдающее "новизной" обсуждение, чуть было не прошло мимо меня smile.gif
Для одного байта я бы сделал как-нить так:
Код
;Input:  r16 - 8bit Binary
;Output: r18:r17:r16 unpacked BCD

    ldi     r18,51
    ldi     r19,10

    mov     r17,r16
    lsr     r17
    inc     r17
    mul     r17,r18
    mov     r17,r1
    mul     r1,r19
    sub     r16,r0
    mov     r1,r17
    lsr     r1
    inc     r1
    mul     r1,r18
    mov     r18,r1
    mul     r1,r19
    sub     r17,r0

16 слов и 20 тактов
singlskv
Цитата(singlskv @ Apr 30 2008, 19:30) *
16 слов и 20 тактов
Не, чего-то первый раз не очень получилось, пробуем еще:
Код
;Input:  r16 - 8bit Binary
;Output: r18:r17:r16 unpacked BCD

    ldi     r17,41
    mul     r16,r17
    swap    r0
    swap    r1
    movw    r16,r0
    mov     r18,r17
    andi    r18,0x0F
    andi    r17,0xF0
    andi    r16,0x0F
    or      r17,r16
    inc     r17
    ldi     r16,10
    mul     r16,r17
    mov     r17,r1
    mul     r0,r16
    mov     r16,r1

16 слов 19 тактов, ну и регистров меньше используем


Нда..., подумал еще..., все нужно делать по-другому sad.gif
Код
;Input:  r16 - 8bit Binary
;Output: r18:r17:r16 unpacked BCD

    ldi     r17,164
    mul     r16,r17
    clr     r18
    lsl     r0
    rol     r1
    rol     r18
    lsl     r0
    rol     r1
    rol     r18
    inc     r1
    ldi     r16,10
    mul     r1,r16
    mov     r17,r1
    mul     r0,r16
    mov     r16,r1

15 слов 18 тактов
Kuznec9999
Цитата(singlskv @ Apr 30 2008, 22:43) *
Код
;Input:  r16 - 8bit Binary
;Output: r18:r17:r16 unpacked BCD

    ldi     r17,164
    mul     r16,r17
    clr     r18
    lsl     r0
    rol     r1
    rol     r18
    lsl     r0
    rol     r1
    rol     r18
    inc     r1
    ldi     r16,10
    mul     r1,r16
    mov     r17,r1
    mul     r0,r16
    mov     r16,r1

15 слов 18 тактов


Спасибо! Это именно то, что нужно! beer.gif
777777
Цитата(singlskv @ Apr 30 2008, 22:43) *
Код
;Input:  r16 - 8bit Binary
;Output: r18:r17:r16 unpacked BCD

    ldi     r17,164
    mul     r16,r17
    clr     r18
    lsl     r0
    rol     r1
    rol     r18
    lsl     r0
    rol     r1
    rol     r18
    inc     r1
    ldi     r16,10
    mul     r1,r16
    mov     r17,r1
    mul     r0,r16
    mov     r16,r1

А нельзя ли пояснить вкратце? Начало я понял: деление на 100 осуществляется умножением на число 32768/100 и результат оказывается в третьем байте, а дальше? И как получается правильный результат несмотря на то что используется округленное частное - 328.
singlskv
Цитата(777777 @ May 2 2008, 19:07) *
А нельзя ли пояснить вкратце? Начало я понял: деление на 100 осуществляется умножением на число 32768/100 и результат оказывается в третьем байте, а дальше? И как получается правильный результат несмотря на то что используется округленное частное - 328.

после умножения на 164 и 2 сдвигов в r18 получаем количество сотен(X/100)
результат для 2 сотен всегда правильный тк нужно было умножить на 163,84 а для
всего 2 сотен достаточно округления до 164
после 2 сдвигов в r1:r0 получаем остаток от деления на 100 нормализованный к диапазону 0-65536,
столько разрядов нам не нужно, хватит и 8 тк нам нужно получить всего 100 значений (0-99),
остается r1 в котором значение 0-99 нормализованное до 0-256
нужно перевести его в десятки и единицы и это делается просто умножением 2 раза на 10, но
для этого нужно скоректировать значение в r1, тк полученный остаток при первом делении и
последующие умножения на 10 всегда отбрасывают младшие разряды, те принцип примерно
как при получении среднего Smed = (Sum(X1,....XN)+N/2)/N для правильного округления в
нужную сторону
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.