BIN 2 BCD for AVR

Do you have a question? Post it now! No Registration Necessary

Translate This Thread From Russian to

Threaded View
Hello Oleg.

02 Nov 04 16:16, you wrote to all:

 OT> Hеобходимо сконвертить 32-ухразрядное двоично число в 10-разрядное
 OT> десятичное.

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

А классически, делением на десять с остатком не подходит?

Alexey


Re: BIN 2 BCD for AVR
Hi Oleg, hope you are having a nice day!


02 Hоя 04, Oleg Terentjev wrote to All:

 OT> 0х0F все хорошо, 0xFF нифига. Корректировать при равенстве, или при
 OT> превышении? А тетрады как лучше проверять? Маскируем, проверяем? Или
 OT> что-то легче есть?

 OT> Хочу именно алгоритм, т.к. разрядность, может быть, придется повышать
 OT> :-( Bye-bye!

1. Загружаем счетчик значением, равным числу бит в исходном двоичном числе.
2. Очищаем результат
3. Сдвигаем исходное число и результат на бит влево, выталкивая старший бит
числа в младший бит результата.
4. Уменьшаем счетчик бит на единицу.
5. Если счетчик == 0, то конец.
6. Если младшая тетрада результата меньше 5, то прибавляем к ней 3.
7. Повторяем п.6 для всех остальных тетрад результата.
8. переходим к п.3

В результате получаем упакованное двоично-десятичное число.

WBR,
    AVB


Re: BIN 2 BCD for AVR
Quoted text here. Click to load it

Очепяточка с условием только вышла у тебя
6. Если младшая тетрада результата больше 4, то прибавляем к ней 3.


Quoted text here. Click to load it

Блин! И ведь пашет.
А название у этого алгоритма есть?
И существует ли что-то подобное для преобразования дробной части числа  
(битов после запятой)?

Попробовал для 32-х разрядов.
Получился такой тестик:

unsigned long long bin2bcd(unsigned int n)
{
    int i;
    unsigned long long l = 0ULL;
        
    for(i=0; i<32; i++)
    {
        l <<= 1;
        if(n&0x80000000)
            l |= 0x00000001;
        n <<= 1;

        if(i=31%)
            break;

        if( (l & 0x000000000FULL) > 0x0000000004ULL)
            l += 0x0000000003ULL;
        if( (l & 0x00000000F0ULL) > 0x0000000040ULL)
            l += 0x0000000030ULL;
        if( (l & 0x0000000F00ULL) > 0x0000000400ULL)
            l += 0x0000000300ULL;
        if( (l & 0x000000F000ULL) > 0x0000004000ULL)
            l += 0x0000003000ULL;
        if( (l & 0x00000F0000ULL) > 0x0000040000ULL)
            l += 0x0000030000ULL;
        if( (l & 0x0000F00000ULL) > 0x0000400000ULL)
            l += 0x0000300000ULL;
        if( (l & 0x000F000000ULL) > 0x0004000000ULL)
            l += 0x0003000000ULL;
        if( (l & 0x00F0000000ULL) > 0x0040000000ULL)
            l += 0x0030000000ULL;
        if( (l & 0x0F00000000ULL) > 0x0400000000ULL)
            l += 0x0300000000ULL;
        if( (l & 0xF000000000ULL) > 0x4000000000ULL)
            l += 0x3000000000ULL;
    }

    return l;
}

Hу а для многоразрядных процессоров выгоднее видимо так:

unsigned long long bin2bcd(unsigned int n)
{
    int i;
    unsigned long long l = 0ULL;
        
    for(i=0; i<32; i++)
    {
        l <<= 1;
        if(n&0x80000000)
            l |= 0x00000001;
        n <<= 1;

        if(i=31%)
            break;

        unsigned long long ll = ( (l>>3) | ((l>>2) & ((l>>1)|l) ) )    &  
0x1111111111ULL;
          l += ll | (ll<<1);
    }

    return l;
}



--
Unrau Alexander

BIN 2 BCD for AVR
Wed, 03 Nov 2004 20:25:34 +0300 Unrau Alexander wrote to All:

UA> Блин! И ведь пашет.
UA> А название у этого алгоритма есть?
UA> И существует ли что-то подобное для преобразования дробной части числа
UA> (битов после запятой)?

    Может кому-то пригодится. Как-то попались две мессаги на эту тему, я их
затарил. А позже они очень пригодились, когда пришлось реализовывать подобное
на MSP430 - помогли быстро разобраться с алгоритмом. Мессаги следующие:

    Первая.

=========Beginning of the citation==============
Subject: Re: BinBcd
Date: 18 февраля 2002 г. 13:10

Привет, Mihail!
 MP> Подскажите алгоритм сабжа для 16 разрядного числ.
 MP> Hужно реализовать на 8051.
 Алгоритм простой: сначала определяется цифра десятков тысяч вычитанием 10000
из исходного числа, затем цифра тысяч последовательным вычитанием 1000, затем
цифры сотен, десятков. Остаток дает цифру единиц.
 Алгоритм менее простой:десятичный эквивалент числа Х можно получить, сдвигая
двоичное число влево и подавая выдвигаемые двоичные цифры в младший разряд
десятичного регистра. Одновременно со сдвигом двоичного регистра необходимо
удваивать содержимое десятичного регистра. Метод основан на представлении числа
в виде полинома Горнера:
        Х=Xn-1*2^(n-1)+Xn-2*2^(n-2)+...+X1*2+X0 - это дв.представление
        X=(...(Xn-1*2+Xn-2)*2+...+X1)*2+X0      - это по Горнеру

PS: А исходник у меня есть в кодах К580ИК80(это не одно и тоже с 8051 ?)

С наилучшими пожеланиями. Alexander.
=========The end of the citation================


    Вторая.


=========Beginning of the citation==============
Subject: Re: BinBcd
Date: 20 февраля 2002 г. 1:16

Привет, Roman!
 >>  Алгоритм менее простой:десятичный эквивалент числа Х можно
 >> получить,
 RS> сдвигая
 >> двоичное число влево и подавая выдвигаемые двоичные цифры в младший
 >> разряд десятичного регистра. Одновременно со сдвигом двоичного
 >> регистра
 RS> необходимо
 >> удваивать содержимое десятичного регистра. Метод основан на
 >> представлении
 RS> числа
 RS> непонятно. точнее то, что тут написано никак не является сабжем.
 Абисняю на примере. Имеем дв.код 1111 , т.е. 15
 1) выдвигаем влево 1-ю ед. из дв.рг
 2) удваиваем сод. дес.рг (0*200%00_0000)
    не забываем, что удвоение - десятичное, т.е. с коррекцией
 3) вдвигаем выдв.1 в дес.рг(0000_0001)
 4) шаг 1
 5) шаг 2 (1*200%00_0010)
 6) шаг 3 (0000_0011)
 7) шаг 1
 8) шаг 2 (3*200%00_0110)
 9) шаг 3 (0000_0111)
 10) шаг 1
 11) шаг 2 Внимание! Самое интересное:
     в данном случае удвоение происходит так:
     т.к. исх.число >= 5 , то вводим коррекцию +3
     получаем 0000_1010, удваиваем ЭТО число (0001_0100)
 12)шаг 3 (0001_0101) Это что? Вроде бы дв/дес. 15. Hе так ли ?

С наилучшими пожеланиями. Alexander.
=========The end of the citation================



    На основе этого код для MSP430 (для IAR'овского ассемблера) выглядит так:

******************************************************
     module  bin2BCD

     public  bin2BCD16

 ; r11 - bit counter

 ; r12 - input binary number
 ; r13 - result (low: 4 digits)
 ; r14 - addr
 ; r15 - result (high: 1 digit)


     rseg    CODE(1)

;----------------------------------------------------
bin2BCD16:
     push    r11
     push    r10

     mov.w   #16,r11
     clr     r13
     clr     r15

;-----------------------------------
;
;    собственно преобраование
;
convert:
     clr     r10
     rla     r12
     rlc     r10

     dadd.w  r13,r13
     dadd.w  r15,r15
     dadd.w  r10,r13
     dadd.w  #0,r15

     dec     r11
     jne     convert
;-----------------------------------

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

unpack:
     call    #extract_byte
     swpb    r13
     call    #extract_byte
     mov.w   r15,r12
     call    #store_byte

     pop     r10
     pop     r11
     ret
;-----------------------------------
extract_byte:
     mov.w   r13,r12
     call    #store_byte
     mov.w   r13,r12
     call    #get_high_nibble
     call    #store_byte
     ret
;-----------------------------------
store_byte:
     bic.w   #0xfff0,r12
     mov.b   r12,0(r14)
     inc     r14
     ret
;-----------------------------------
get_high_nibble:
     rlc.b   r12
     rlc.b   r12
     rlc.b   r12
     rlc.b   r12
     rlc.b   r12
 ret
;------------------------------------------------------------

     end
******************************************************


    Сам алгоритм очень короткий и эффективный благодаря наличию арифметических
команд с десятичной коррекцией (то самое прибавление по условию).

    Потом, правда, нашел похожую реализацию в одной из аппликух, но не жалею о
проделанной работе, было интересно разобраться. :)



    Для AVR есть у Atmel подобная функция, написанная на асме. Адаптированная
под IAR она выглядит так:


    Сишный прототип: void bin2BCD16(word num, byte* Buf);

******************************************************
     module     Num_2_BCD_Module

     public   bin2BCD16

     rseg     CODE:CODE:NOROOT(1)

;---------------------------------------------------------------------------
;*
;* "bin2BCD16" - 16-bit Binary to BCD conversion
;*
;* This subroutine converts a 16-bit number (fbinH:fbinL) to a 5-digit
;* packed BCD number represented by 3 bytes (tBCD2:tBCD1:tBCD0).
;* MSD of the 5-digit number is placed in the lowermost nibble of tBCD2.
;*
;* 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
;*
;---------------------------------------------------------------------------

;***** Subroutine Register Variables
#define     zl               r30
#define     zh               r31

#define    AtBCD0            0           // address of tBCD0
#define    AtBCD2            1           // address of tBCD2

#define    tBCD0             r0          // BCD value digits 1 and 0
#define    tBCD1             r1          // BCD value digits 3 and 2
#define    tBCD2             r2          // BCD value digit 4
#define    fbinL             r16         // binary value Low byte
#define    fbinH             r17         // binary value High byte
#define    cnt16a            r20         // loop counter
#define    tmp16a            r21         // temporary value

#define    rtmp              tmp16a
#define    BCD_AddrLow       r18
#define    BCD_AddrHigh      r19


bin2BCD16:
     ldi     cnt16a,16       ;Init loop counter
     clr     tBCD2           ;clear result (3 bytes)
     clr     tBCD1
     clr     tBCD0
     clr     zh              ;clear ZH (not needed for AT90Sxx0x)

bBCDx_1:
     lsl     fbinL           ;shift input value
     rol     fbinH           ;through all bytes
     rol     tBCD0           ;
     rol     tBCD1
     rol     tBCD2
     dec     cnt16a          ;decrement loop counter
     brne    bBCDx_2         ;if counter not zero

                             ;fill array and ...
     mov     zl,BCD_AddrLow
     mov     zh,BCD_AddrHigh
     mov     rtmp,tBCD0
     andi    rtmp,0x0f
     st      z+,rtmp         ;BCD[0] = value0  (LSD)
     swap    tBCD0
     mov     rtmp,tBCD0
     andi    rtmp,0x0f
     st      z+,rtmp         ;BCD[1] = value1
     mov     rtmp,tBCD1
     andi    rtmp,0x0f
     st      z+,rtmp
     swap    tBCD1           ;BCD[2] = value2
     mov     rtmp,tBCD1
     andi    rtmp,0x0f
     st      z+,rtmp         ;BCD[3] = value3
     st      z,tBCD2         ;BCD[4] = value4  (MSD)
     ret                     ; ... return

bBCDx_2:
     ldi     r30,AtBCD2+1    ;Z points to result MSB + 1

bBCDx_3:
     ld      tmp16a,-z       ;get (Z) with pre-decrement
     subi    tmp16a,-$03     ;add 0x03
     sbrc    tmp16a,3        ;if bit 3 not clear
     st      z,tmp16a        ;       store back
     ld      tmp16a,z        ;get (Z)
     subi    tmp16a,-$30     ;add 0x30
     sbrc    tmp16a,7        ;if bit 7 not clear
     st      z,tmp16a        ;       store back
     cpi     zl,AtBCD0       ;done all three?
     brne    bBCDx_3         ;loop again if not
     rjmp    bBCDx_1

end

    Это, кстати, обсосано в соответствующей аппликухе. Только там принцип не
объяснен (afair), а только последовательность действий.

--
H.Z.

h.z<antispam::at>ngs<antispam::period>ru

We've slightly trimmed the long signature. Click to see the full one.
Re: BIN 2 BCD for AVR
День добрый!

Quoted text here. Click to load it
..............

А не писал ли кто подобный код на С (8051) и не поделится ли? - сэкономит
время на упражнения самому.

С уважением, Юрий Копылов inlog(@)mtu-net.ru




Re: BIN 2 BCD for AVR
6-Nov-04 09:18 Yuri Kopylov wrote to Harry Zhurov:

Quoted text here. Click to load it

YK> А не писал ли кто подобный код на С (8051) и не поделится ли? - сэкономит
YK> время на упражнения самому.

Вдогонку. Этот алгоритм - это как бы "по определению", мы просто берём
запись числа в виде

 sum( A[n] * E^n )

где A[n] - n-я цифра числа,
E - основание системы счисления,
'^' - "в степени"

представив A[n] и E исходной системы счисления в виде чисел целевой
системы и производим все вычисления в целевой системе.
Естественно, как тут уже говорилось, для упрощения вычислений сумму
расписываем по Горнеру.
При переводе из двоичной системы A[n] - однобитовые знаки а E==2
и "умножить на E" в цепочке вместе с прибавлением очередного A[n]
превращается в сдвиг и последующую десятичную коррекцию.

wbr,
--
/* Oleksandr Redchuk, Brovary, Ukraine */
/* real '\x40' real '\x2E' kiev '\x2E' ua     */


Re: BIN 2 BCD for AVR
6-Nov-04 09:18 Yuri Kopylov wrote to Harry Zhurov:

Quoted text here. Click to load it
YK> ..............

YK> А не писал ли кто подобный код на С (8051) и не поделится ли? - сэкономит
YK> время на упражнения самому.

Если на C, то причём тут 8051?

Чесслово, очень фигово писать не на С, а на "С для 8051", "С для XXX", "С
для YYY". Практически полностью теряется смысл писания на C, потом для
другого процессора хоть переписывай, хоть заново пиши. Это говорит
печальный опыт 10-летней давности, когда в погоне за призрачной
"эффективностью" я писал не просто "на C для 8051", а вообще
"на AVOCET C51", используя всякие фокусы, основанные на знании того,
как ЭТОТ компилятор компилирует те или иные конструкции.
В частности, в программе нигде не было
 if(a != b)
было
 if(a^b)

В итоге при полной переделке проекта под новое железо, но тоже на 8051,
и переходе на Keil - я те места, где было действительно критично -
переписал на ассемблере (число трок асма по сравнению спервым вариантом
вырасло раза в два, с 10 до 20% строк проекта), а остальное писал на
"гораздо более натуральном С".

Итого "а если для 8051, то почему не на асме?".

Я когда-то кидал сюда куски на асме с соглашениями о регистрах для вызова из
Keil C

bin -> packed BCD
packed -> unpacked
unpacked -> ASCII

единое компактное тело для работы с 8,16,24,32 - битными целыми.
Дело в том, что у 51-го есть команда десятичной коррекции после сложения,
которая очень хорошо в этих алгоритмах исползуется, причём и для
преобразования тетрады в ascii 0-9,A-F тоже. Это "ещё более когда-то"
кидал сюда Василевский, но для какой-то фиксированной разрядности
и фиксированной длины ASCII-выхода. А году в 98 я переписал под переменную
длину (как во входных битах, так и в выходных цифрах, например, заданием
нужных параметров при вызове word2ascii для выдачи чисел 0..9999
в 4-байтовый выходной массив).

Лень сейчас рыться на компакте с архивом проектов, заново выковыривать,
переводить комментарии... Должно быть в архивах эхи.

wbr,
--
/* Oleksandr Redchuk, Brovary, Ukraine */
/* real '\x40' real '\x2E' kiev '\x2E' ua     */


Re: BIN 2 BCD for AVR
Добрый день!


Quoted text here. Click to load it

    Но ведь понятно же, что я имел ввиду - у меня и так сейчас есть
процедуры перевода форматов чисел, которые уже давно тягаю из проекта в
проект. На Keil-С для 8051. А компилятор тут при том, что у многих м.б.
разные библиотеки на циклический сдвиг, например, наличие или отсутствие к-д
дес. коррекции и пр. Либо м.б. asm-вставки. И вопрос-то не в том, чтобы
написать код на С - текст-то действительно может быть универсальным и
переносимым. А вопрос в скорости, оптимальности и занимаемой памяти. И даже
после того, как
взял чужой С-код, обычно есть возможность его сократить при адаптации хотя
бы за счет разных вариантов использования памяти - data или idata,
использования common-переменных и пр.

Например, на моем процессоре AT89S53 по-разному написанная процедура

void long_to_ascii(long d)  // char знак + 7 цифр = 8 символов

с использованием операций вида         с = (d % 10000)/1000 | 0x30;   //
Тысячи
выполняется около 3.5 мсек,
а с использованием
d -= ((long)c)*100000;    c = (char)(d/10000);

не более 2 мсек, хотя и на 160 байт длиннее.

Вот об этом я и говорил - может, можно еще быстрее и короче. Кому что когда
нужно.

Quoted text here. Click to load it
Лично для меня сейчас на С - намного быстрее написать и изменить.
И в конкретном случае (на С) общий код получается короче и быстрее
универсального, поскольку моя процедура перевода не возвращает некоторую
строку как параметр, а внутри себя пишет результат в разные места, в том
числе в буфер вывода RS-232. Еще и учитывается проблема с местом под стек.
Да и нужен мне
пока перевод фиксированной длины.

Quoted text here. Click to load it
    Попробую посмотреть. Спасибо.

WBR  Юрий Копылов




Re: BIN 2 BCD for AVR
Sat Nov 06 2004 20:41, Oleksandr Redchuk wrote to "Yuri Kopylov":


 OR> Чесслово, очень фигово писать не на С, а на "С для 8051", "С для XXX", "С
 OR> для YYY". Практически полностью теряется смысл писания на C, потом для
 OR> другого процессора хоть переписывай, хоть заново пиши. Это говорит
 OR> печальный опыт 10-летней давности, когда в погоне за призрачной
 OR> "эффективностью" я писал не просто "на C для 8051", а вообще
 OR> "на AVOCET C51", используя всякие фокусы,

 Я стараюсь писать по-возможности портабельно и прозрачно, однако все равно
 случалось наступать на хорошие грабли. Однажды пришлось портировать код на
 TMS320C55xx, у которого в С нет 8-битного типа. В коде много где
использовалось
 неявное обрезание char по 8 битам, что привело к самым разнообразным
проблемам.
 
 VLV
  

" Evil will prevail because good is dumb " (c)  Dart  Weider


Re: BIN 2 BCD for AVR
7-Nov-04 20:25 Vladimir Vassilevsky wrote to Oleksandr Redchuk:

OR>> Чесслово, очень фигово писать не на С, а на "С для 8051", "С для XXX", "С
OR>> для YYY". Практически полностью теряется смысл писания на C, потом для
OR>> другого процессора хоть переписывай, хоть заново пиши. Это говорит

VV>  Я стараюсь писать по-возможности портабельно и прозрачно, однако все
VV> равно
VV>  случалось наступать на хорошие грабли. Однажды пришлось портировать код
VV> на TMS320C55xx, у которого в С нет 8-битного типа. В коде много где
 Дык я и не говорю, что С асолютно портабельный.
 Но самому себе усложнять будущее, применяя в "общеупотребительном"
коде небольшого размера фичи, завязанные на пару
кристалл+производитель_компилятора - считаю "несколько необдуманным".

wbr,
--
/* Oleksandr Redchuk, Brovary, Ukraine */
/* real '\x40' real '\x2E' kiev '\x2E' ua     */


Re: BIN 2 BCD for AVR
Hемедленно нажми на RESET, Yuri Kopylov!


 >>  Абисняю на примере. Имеем дв.код 1111 , т.е. 15
 >>  1) выдвигаем влево 1-ю ед. из дв.рг
 YK> ..............

 YK> А не писал ли кто подобный код на С (8051) и не поделится ли? - сэкономит
 YK> время на упражнения самому.

  В любой C библиотеке, функция div.


Re: BIN 2 BCD for AVR

сообщил/сообщила в новостях
Quoted text here. Click to load it
сэкономит
Quoted text here. Click to load it

Не бросит кто текст? В моих компиляторах нет такого в явном виде.

С уважением, Юрий



Re: BIN 2 BCD for AVR
Hемедленно нажми на RESET, Alexey Boyko!


 OT>> Hеобходимо сконвертить 32-ухразрядное двоично число в 10-разрядное
 OT>> десятичное.
 OT>> Хочу именно алгоритм, т.к. разрядность, может быть, придется повышать
 AB> А классически, делением на десять с остатком не подходит?

  Классически нужно 10 операций деления (10*32*N сдвигов и сложений),
а не классически -- 32 сдвига, 32 двоично-десятичных сложения с переносом.
Если AVR, вот хоть убей не помню, имеет команду BCD коррекции после сложения,
будет очень быстро.


Re: BIN 2 BCD for AVR
Hi Unrau, hope you are having a nice day!


03 Hоя 04, Unrau Alexander wrote to All:

 >> 0, то конец. 6. Если младшая тетрада результата меньше 5, то
 >> прибавляем к ней 3.
 UA> Очепяточка с условием только вышла у тебя
 UA> 6. Если младшая тетрада результата больше 4, то прибавляем к ней 3.

Да, это так. Просто восстанавливал алгоритм по ассемблерному исходнику, поэтому
неправильно посмотрел условие.

 >> 7. Повторяем п.6 для всех остальных тетрад результата.
 >> 8. переходим к п.3
 UA> Блин! И ведь пашет.
 UA> А название у этого алгоритма есть?

Hаверное есть. Вообще это модификация алгортима для процессоров без команды
двоично десятичной коррекции. Поэтому, для
того чтобы не учитытвать флаги переноса и десятичного переноса сначала
выполняется коррекция, потом сдвиг. Чисто
алгоритмически нужно сначала делать сдвиг (обычно сложением каждого байта
результата с самим собой), а затем уже вызов
команды десятичной коррекции каждого байта результата.

Т.е. на PIC18 это вырождается в такую последовательность:

    rlcf    src0,F
    rlcf    src1,F
    rlcf    src2,F
    rlcf    src3,F

    movf    AARGB0,W
    addwfc  AARGB0,F
    daw     AARGB0,F
    movf    AARGB1,W
    addwfc  AARGB1,F
    daw     AARGB1,F

и т.д. вот только daw на pic18 не работает корректно, посему приходится вместо
3-х команд писать 8.

 UA> И существует ли что-то подобное для преобразования дробной части
 UA> числа (битов после запятой)?

Hе знаю. Обычно сначала умножают на 10^n, где n-число знаков после запятой,
приводят к целому, затем преобразовывают.

 UA> Попробовал для 32-х разрядов.
 UA> Получился такой тестик:

Красиво, правда на мой взгляд этот алгоритм гораздо эффективнее должен работать
в ассемблерной реализации.

WBR,
    AVB


BIN 2 BCD for AVR
 Приветствую тебя, Alexey

Сpд Hоя 03 2004 22:40, Alexey V Bugrov отписал к Unrau Alexander:

 -=[поскипано]=-
 >>> 8. переходим к п.3
 UA>> Блин! И ведь пашет.
 UA>> А название у этого алгоритма есть?

 AB> Hаверное есть. Вообще это модификация алгортима для процессоров без
 AB> команды двоично десятичной коррекции. Поэтому, для того чтобы не
 AB> учитытвать флаги переноса и десятичного переноса сначала выполняется
 AB> коррекция, потом сдвиг.
 А как будет выглядеть исходный алгоритм? С этим разобрался, спасибо всем.
 Флаг полупереноса имеется, но, imho, он используется при сложении BCD чисел.

 AB> Чисто алгоритмически нужно сначала делать
 AB> сдвиг (обычно сложением каждого байта результата с самим собой), а
 AB> затем уже вызов команды десятичной коррекции каждого байта результата.

 AB> Т.е. на PIC18 это вырождается в такую последовательность:
-=[поскипано]=-
 AB> Красиво, правда на мой взгляд этот алгоритм гораздо эффективнее
 AB> должен работать в ассемблерной реализации.
 Естетсственно.  Hе в топик, но... Спектрум с 48 кб играл в шахматы по силе
примерно так же, как как 286 с 640 кб. Потому что код "вылизывали". А сейчас
embedded идет по пути IBM-PC семейства - зачем думать, если можно кристалл
поболе поставить? Если что - в нетмейл.

 Bye-bye!


Re: BIN 2 BCD for AVR
Приветствую Вас, Yuri!

Однажды 06 Hоя 04 в 12:18, Yuri Kopylov писал(а) к Harry Zhurov...

Quoted text here. Click to load it
YK> ..............
YK>
YK> А не писал ли кто подобный код на С (8051) и не поделится ли? -
YK> сэкономит время на упражнения самому.

 Hе совсем понимаю о чем ты говоpишь, но я писал под 5 знаковый статический ЖКИ
готового устpойства (пpошивку пеpеделывал под цели заказчика). Для 80C31 на
3.58MHz. Там и меандp инвеpсии и скpывание нулей/символов, мигание и т.п. Hо
то,
что ты спpашиваешь - это одна стpочка. Вот она:

 for(i =4; i>=1; i--) {dig[i] = N%10; N = N/10; f_visible[i] = visible;}

 N - это копия числа, пеpеданного в функцию. dig[5] - массив байтов. Сpазу же
начальная видимость выставляется, ведь неизвестно заpанее "0" отобpазит сегмент
или "1" (меандpом пpеpывание заведует). В следующей стpоке (не пpивожу) в
глобальный массив соответствия семисегментным знакам (цифpам), но ты пpо это не
пpосил. Hавеpное, можно было быстpую асм вставку сделать, но это была моя
пеpвая
пpога под x51 вообще, и втоpая на C в эхотажном пpиложении. И вообще я не
пpогpаммист :)
 Или ты пpо то как деление сдвигами заменить на C?

С уважением, Виталий.

... -|O|-

Re: BIN 2 BCD for AVR
Привет!


Quoted text here. Click to load it
.........

    См. мой ответ OR - вопрос в скорости выполнения и занимаемой памяти.
По моим измерениям, быстрее оказалось использовать деление/умножение вместо
% и линейная программа на 8 десятичных знаков вместо цикла.
Попробую померять в симуляторе твою конструкцию -результат напишу.
Сейчас у меня используется следующий вариант (аналогично делаю перевод
float_to_ascii - писал неск. лет назад, когда начал писать на С вместо asm):

void long_to_ascii(long d)  // знак + 7 цифр = 8 знаков,  тестовое время
выполнения 1.943...1.961 msec при 24 мГц
{
char c;

 if (d < 0) {que[qlen++] = '-'; d = -d;}
  else que[qlen++] = '+';

 c = (char)(d/1000000);
 que[qlen++] = c | 0x30;
// Миллион
 d -= ((long)c)*1000000;     c = (char)(d/100000);
 que[qlen++] = c | 0x30;
// Сотни тысяч
 d -= ((long)c)*100000;     c = (char)(d/10000);
 que[qlen++] = c | 0x30;
// Десятки тысяч
 d -= ((long)c)*10000;       c = (char)(d/1000);
 que[qlen++] = c | 0x30;
// Тысячи
 d -= ((long)c)*1000;         c = (char)(d/100);
 que[qlen++] = c | 0x30;
// Сотни
 d -= ((long)c)*100;             c = (char)(d/10);
 que[qlen++] = c | 0x30;
// Десятки
 c = (char)(d-((long)c)*10);
que[qlen++] = c | 0x30;
// Единицы
}

С уважением, Юрий Копылов




Re: BIN 2 BCD for AVR
Привет!


Quoted text here. Click to load it

    8051, 22.1184 МГц. Перевожу в символы число 1234567 dec.

1. Программа на базе твоей строчки (выше) короче моего линейного варианта на
~ 479 байтов
    Время выполнения тестового примера - 4.63867 мсек

2. Мой текущий вариант (линейная программа и деления на 10 и вычитания):
    Время выполнения тестового примера - 2.36111 мсек

В 2 раза быстрее. Вот потому и хотел попробовать что-либо
поинтеллектуальнее, чем простое деление на 10 и вычитание. Тем более, если
микро имеет к-ды BCD и если есть возможность при этом не лезть в asm.

WBR Юрий Копылов



Re: BIN 2 BCD for AVR
7-Nov-04 14:45 Yuri Kopylov wrote to Vitaliy Romaschenko:


Quoted text here. Click to load it

YK>     8051, 22.1184 МГц. Перевожу в символы число 1234567 dec.

YK> 1. Программа на базе твоей строчки (выше) короче моего линейного варианта
YK> на
YK> ~ 479 байтов
YK>     Время выполнения тестового примера - 4.63867 мсек

YK> 2. Мой текущий вариант (линейная программа и деления на 10 и вычитания):
YK>     Время выполнения тестового примера - 2.36111 мсек
YK> В 2 раза быстрее.
 Понятно почему - одно деление заменено на умножение, которое гораздо
быстрее.

YK> поинтеллектуальнее, чем простое деление на 10 и вычитание. Тем более,
YK> если
YK> микро имеет к-ды BCD и если есть возможность при этом не лезть в asm.
Я даже не вникал - какие у Keil есть inline функции "ближе к железу",
кроме просто необходимых cli() sei().

Продолжаю утверждать, что если какой-то кусок типа этого конвертора
нужно вылизать на объём и/или скорость, то гораздо правильнее его
выписать на ассемблере - это проще, чем извращаться на С и
сопровождаться/изменяться оно будет не сложнее, чем "якобы С-шный код".
В данном конкретном случае его в строках будет ненамного больше,
чем "С"-шного.

Поэтому сейчас продолжаю обсуждать "стандартно-С-шные" методы.

 Непонятно почему, но Keil не даёт в стандартной библиотеке
функций div и ldiv, ведь тело для них в библиотеке есть гарантированно,
надо только засунуть его в нужную обёртку.

#include <stdlib.h>
div_t div(int num, int denom);
ldiv_t ldiv(long num, long denom);

Дело в том, что внутренняя библиотечная функция деления в процессе рабоы
всегда получает и частное, и остаток. При / вызывается эта функция и
берётся частное, при % - ещё раз вызывается она же и берётся остаток.
Функции div, ldiv просто возвращают оба значения сразу - и частное,
и остаток.
Итого

int8_t dig[4];
div_t dt;

dt.quot = N;
for(i =3; i>=1; --i) {
        dt = div( dt.quot, 10);
        dig[i] = dt.rem;
}
dig[0] = dt.quot;

Для AVR (mega64) этот код несколько длиннее, чем с / % (в основном за счёт
увеличенного количества обращений к памяти), но в два раза быстрее
(что вполне естественно).
И немного медленнее, чем линейная программа с делением и вычитанием
умноженного (не стал разбираться почему), зато более чем в 2 раза короче.

wbr,

--
/* Oleksandr Redchuk, Brovary, Ukraine */
/* real '\x40' real '\x2E' kiev '\x2E' ua     */


Re: BIN 2 BCD for AVR

Quoted text here. Click to load it

это то понятно, я просто думал может как есть без  умножения.

Quoted text here. Click to load it

Я писал тестик дабы проверить алгоритм и понять как он пашет.
Hу а его оптимальная реализация в каждом конкретном случае может быть  
разная.
Hа некоторых платформах и 10 раз поделить на 10 более клёва чем этот  
алгоритм.


--
Unrau Alexander

Site Timeline