BIN 2 BCD for AVR

Nov 02, 2004 36 Replies

Hello, Kirill Frolov !

á ÚÁÞÅÍ ÅÓÌÉ ÎÅ × ÐÒÅÄÅÌÁÈ ÏÄÎÏÊ? HÏ ×ÏÐÒÏÓ ÄÁÖÅ ÎÅ × ÜÔÏÍ. åÓÌÉ ÕÖ ×ÙÂÒÁÎ ÔÁËÏÊ ÓÐÏÓÏÂ, ÎÕÖÄÙ × ÏÐÔÉÍÉÚÁÃÉÉ subj, ÏÓÏÂÅÎÎÏ ÐÏ ÓËÏÒÏÓÔÉ, ÕÖÅ ÎÅÔ. ó Õ×ÁÖÅÎÉÅÍ, äÉÍÁ ïÒÌÏ×.

Wed, 03 Nov 2004 20:25:34 +0300 Unrau Alexander wrote to All:

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

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

Первая.

=========Beginning of the citation============== From: "Alexander Volkov" snipped-for-privacy@p55.f.n5051.z2.fidonet.org>

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============== From: "Alexander Volkov" snipped-for-privacy@p55.f.n5051.z2.fidonet.org>

Subject: Re: BinBcd Date: 20 февраля 2002 г. 1:16

Привет, Roman! >> Алгоритм менее простой:десятичный эквивалент числа Х можно >> получить, RS> сдвигая >> двоичное число влево и подавая выдвигаемые двоичные цифры в младший >> разряд десятичного регистра. Одновременно со сдвигом двоичного >> регистра RS> необходимо >> удваивать содержимое десятичного регистра. Метод основан на >> представлении RS> числа RS> непонятно. точнее то, что тут написано никак не является сабжем. Абисняю на примере. Имеем дв.код 1111 , т.е. 15 1) выдвигаем влево 1-ю ед. из дв.рг 2) удваиваем сод. дес.рг (0*2=0000_0000) не забываем, что удвоение - десятичное, т.е. с коррекцией 3) вдвигаем выдв.1 в дес.рг(0000_0001) 4) шаг 1 5) шаг 2 (1*2=0000_0010) 6) шаг 3 (0000_0011) 7) шаг 1 8) шаг 2 (3*2=0000_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), а только последовательность действий.

День добрый!

..............

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

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

6-Nov-04 09:18 Yuri Kopylov wrote to Harry Zhurov:

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

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

sum( A[n] * E^n )

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

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

wbr,

6-Nov-04 09:18 Yuri Kopylov wrote to Harry Zhurov:

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,

ðÒÉ×ÅÔÓÔ×ÕÀ ÷ÁÓ, Yuri! ïÄÎÁÖÄÙ 06 HÏÑ 04 × 12:18, Yuri Kopylov ÐÉÓÁÌ(Á) Ë Harry Zhurov...

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|-

Добрый день!

Oleksandr Redchuk snipped-for-privacy@real.kiev.ua> пишет

Но ведь понятно же, что я имел ввиду - у меня и так сейчас есть процедуры перевода форматов чисел, которые уже давно тягаю из проекта в проект. На 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 байт длиннее.

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

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

Попробую посмотреть. Спасибо.

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

Привет!

Vitaliy Romaschenko snipped-for-privacy@p6.f.n5060.z2.fidonet.org> пишет

См. мой ответ 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; // Единицы }

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

Привет!

Vitaliy Romaschenko snipped-for-privacy@p6.f.n5060.z2.fidonet.org> пишет

8051, 22.1184 МГц. Перевожу в символы число 1234567 dec.
  1. Программа на базе твоей строчки (выше) короче моего линейного варианта на ~ 479 байтов Время выполнения тестового примера - 4.63867 мсек
  2. Мой текущий вариант (линейная программа и деления на 10 и вычитания): Время выполнения тестового примера - 2.36111 мсек

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

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

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

ðÒÉ×ÅÔÓÔ×ÕÀ ÷ÁÓ, àpÉÊ! ïÄÎÁÖÄÙ 07 HÏÑ 04 × 17:45, Yuri Kopylov ÐÉÓÁÌ(Á) Ë Vitaliy Romaschenko...

YK> ÷ÒÅÍÑ ×ÙÐÏÌÎÅÎÉÑ ÔÅÓÔÏ×ÏÇÏ ÐÒÉÍÅÒÁ - 2.36111 ÍÓÅË YK>

YK> ÷ 2 ÒÁÚÁ ÂÙÓÔÒÅÅ. ÷ÏÔ ÐÏÔÏÍÕ É ÈÏÔÅÌ ÐÏÐÒÏÂÏ×ÁÔØ ÞÔÏ-ÌÉÂÏ YK> ÐÏÉÎÔÅÌÌÅËÔÕÁÌØÎÅÅ, ÞÅÍ ÐÒÏÓÔÏÅ ÄÅÌÅÎÉÅ ÎÁ 10 É ×ÙÞÉÔÁÎÉÅ. ôÅÍ ÂÏÌÅÅ, YK> ÅÓÌÉ ÍÉËÒÏ ÉÍÅÅÔ Ë-ÄÙ BCD É ÅÓÌÉ ÅÓÔØ ×ÏÚÍÏÖÎÏÓÔØ ÐÒÉ ÜÔÏÍ ÎÅ ÌÅÚÔØ × YK> asm.

ñÓÎÏ. óÂÉÌÏ Ó ÔÏÌËÕ, ÞÔÏ ÔÙ ÓËÁÚÁÌ ÉÍÅÎÎÏ ÎÁ C. á ÐpÏ ÐpÉ×ÑÚËÕ Ë ËÏÎËpÅÔÎÏÍÕ ËÏÍÐÉÌÌÑÔÏpÕ É ËÁÍÎÀ - ÎÅÏÞÅ×ÉÄÎÏ. ñ ÌÅÎÉ×ÙÊ É ÚÁÎÉÍÁÀÓØ ÏÐÔÉÍÉÚÁÃÉÅÊ ÔÏÌØËÏ ÔÅÈ ×ÅÝÅÊ, ËÏÔÏpÙÅ ÍÏÇÕÔ ÐÏ×ÌÉÑÔØ ÎÁ ÐÏÌØÚÏ×ÁÔÅÌØÓËÉÅ ÈÁpÁËÔÅpÉÓÔÉËÉ ÇÏÔÏ×ÏÇÏ ÕÓÔpÏÊÓÔ×Á. ô.Å. ÐpÉÄÅpÖÉ×ÁÀÓØ ÄÅ×ÉÚÁ: "ìÕÞÛÅÅ - ×pÁÇ ÈÏpÏÛÅÇÏ". èÏÔÑ, ×ÓÑËÏÅ ÂÙ×ÁÅÔ × ÎÅËÏÍÍÅpÞÅÓËÉÈ ÃÅÌÑÈ... ó Õ×ÁÖÅÎÉÅÍ, ÷ÉÔÁÌÉÊ.

... -|O|-

7-Nov-04 14:45 Yuri Kopylov wrote to Vitaliy Romaschenko:

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,

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,

Hello Yuri!

07 Nov 04 16:49, you wrote to Vitaliy Romaschenko:

YK> óÍ. ÍÏÊ ÏÔ×ÅÔ OR - ×ÏÐÒÏÓ × ÓËÏÒÏÓÔÉ ×ÙÐÏÌÎÅÎÉÑ É ÚÁÎÉÍÁÅÍÏÊ YK> ÐÁÍÑÔÉ. ðÏ ÍÏÉÍ ÉÚÍÅÒÅÎÉÑÍ, ÂÙÓÔÒÅÅ ÏËÁÚÁÌÏÓØ ÉÓÐÏÌØÚÏ×ÁÔØ YK> ÄÅÌÅÎÉÅ/ÕÍÎÏÖÅÎÉÅ ×ÍÅÓÔÏ % É ÌÉÎÅÊÎÁÑ ÐÒÏÇÒÁÍÍÁ ÎÁ 8 ÄÅÓÑÔÉÞÎÙÈ ÚÎÁËÏ× YK> ×ÍÅÓÔÏ ÃÉËÌÁ. JFYI: ÷Ù ÎÉËÏÇÄÁ ÎÅ ÚÁÄÕÍÙ×ÁÌÉÓØ, ÞÔÏ ÃÅÌÏÅ ÄÅÌÅÎÉÅ ÄÁÅÔ ÎÅ ÏÄÉÎ, Á ä÷á ÒÅÚÕÌØÔÁÔÁ ÏÄÎÏ×ÒÅÍÅÎÎÏ, É ÎÅÄÏÏÐÔÉÍÉÚÉÒÏ×ÁÎÎÙÊ ËÏÍÐÉÌÑÔÏÒ ÂÕÄÅÔ ÄÅÌÉÔØ Ä×Á ÒÁÚÁ ÄÌÑ ÐÏÌÕÞÅÎÉÑ dig[i] É N? á ÕÍÎÏÖÅÎÉÅ ÏÂÙÞÎÏ ÂÙÓÔÒÅÅ ÄÅÌÅÎÉÑ, ÐÏÜÔÏÍÕ ÎÅÍÕÄÒÅÎÏ, ÞÔÏ ÄÅÌÅÎÉÅ/ÕÍÎÏÖÅÎÉÅ ÂÙÓÔÒÅÅ Ä×ÕÈ ÄÅÌÅÎÉÊ.

Anatoly

÷ÏÐÒÏÓ × ÆÏÒÍÅ ÐÒÅÄÓÔÁ×ÌÅÎÉÑ, ÒÁÚÎÙÈ ÆÏÒÍÁÔÁÈ, ÏÛÉÂËÁÈ ÏËÒÕÇÌÅÎÉÑ É ÔÏÍÕ ÐÏÄÏÂÎÏÍ. äÁ É ÂÏÌÅÅ ÐÒÏÓÔÏÇÏ ÓÐÏÓÏÂÁ ÐÅÒÅÄÁÔØ ÞÉÓÌÏ ÞÅÍ printf É scanf Ñ ÐÏÞÅÍÕ-ÔÏ ÎÅ ÚÎÁÀ. ä×ÏÉÞÎÕÀ ÚÁÐÉÓØ ÎÕÖÎÏ ËÁË-ÔÏ ÒÁÚÂÉÒÁÔØ Åݣ.

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required