Двоично-десятичное преобразование встречается на практике чаще, чем десятично-двоичное, но реализуется немного сложнее. Приходится решать обратную задачу определения десятичных коэффициентов по известному двоичному полиному.
В соответствии с (1) все коэффициенты di (разряды десятичного числа, подлежащие определению) могут быть найдены последовательным делением D на 10i. Так после первого деления D/10n-1 получим старший разряд dn-1 как частное и остаток от деления dn-2*10n-2 + … + d1*101 + d0*100. Потом делением остатка на 10n-2 получим очередной разряд dn-2 и т.д.
Подпрограмма преобразования однобайтового двоичного числа в 3-разрядное десятичное приведена ниже. В ней пришлось использовать две операции деления на 100 и на 10.
; R18:R17:R16 <- R16 ; R18:R17:R16 – десятичное число после преобразования ; (R16 - единицы, R17 - десятки, R18 - сотни) ; R16 –двоичное преобразуемое число, лежащее в диапазоне 0…255 bin8_dec3: clr R17 ;очищаем R17,R18 при входе clr R18 ;в подпрограмму subi R16,100 ;вычитаем 100 пока не получим inc R18 ;отрицательную разность brcc PC-2 dec R18 ;корректируем счётчик сотен subi R16,-100 ;корректируем остаток, добавляя 100 subi R16,10 ;вычитаем 10 пока не получим inc R17 ;отрицательную разность brcs PC-2 dec R17 ;корректируем счётчик десятков subi R16,-10 ;корректируем остаток, добавляя 10 ret
Преобразование однобайтовых чисел по (1), как мы видим, вполне оправдано. Но если понадобиться перевести в десятичное представление, например, 3-байтовое двоичное число, то необходимо будет использовать несколько подпрограмм деления на 10,100,1000 и т.д. Схема Горнера же позволяет обойтись только делением на 10, не зависимо от размера преобразуемого числа.
Первое деление D из (2) на 10 даст самый младший разряд d0 в виде остатка и частное …(dn-1*10 + dn-2)*10 + … + d1. Произведя деление, полученного в предыдущем цикле частного, на 10, определяем следующий по старшинству разряд d1 и т.д. Определение коэффициентов di по схеме Горнера, в отличии от (1), ведется от младшего разряда d0 к старшему dn-1.
Подпрограмма преобразования 2-байтового двоичного числа в 5-разрядное десятичное (десятичные коэффициенты d4…d0 хранятся в SRAM микроконтроллера):
; [YH:YL] <- R17:R16 ; [YH:YL] – десятичное число после преобразования ; (косвенно адресуется через YH:YL) ; R17:R16 – двоичное преобразуемое число, лежащее ; в диапазоне (0…0xFFFF) ; R18,R19,R20 – вспомогательные регистры ; decnum – адрес десятичного числа в ОЗУ bin16_dec5: ldi YL,low(decnum) ;заносим в указатель Y адрес ldi YH,high(decnum) ;начала массива чисел d0…d4 ldi R20,4 ;инициализируем счётчик десятичных цифр bd1: clr R18 ;обнуляем вспомогательный регистр R18 ldi R19,16 ;инициализируем счётчик циклов при делении bd2: lsl R16 ;здесь производится деление V(D)/10 rol R17 ;частное снова заносится в R17:R16, rol R18 ;а остаток в R18 = di andi R16,0xFE cpi R18,10 brcs bd3 subi R18,10 ori R16,0x01 bd3: dec R19 brne bd2 st Y+,R18 ;заносим все di в ОЗУ dec R20 brne bd1 ;деление производится n-1 раз st Y+,R16 ;заносим старший коэффициент dn-1 в ОЗУ ret
Для двоично-десятичного преобразования существует еще один алгоритм, связанный с использованием двоично-десятичной коррекции результата. По сравнению с приведёнными выше примерами, он требует больших затрат памяти программ и регистров но выполняется с наибольшей скоростью.
Процессор производит все арифметические операции по законам двоичной арифметики и поэтому интерпретирует любые данные именно как двоичные числа. Соответственно, результатом таких операций также являются числа, представленные в двоичном формате. Если используется какая либо иная форма представления чисел, то почти наверняка, любые действия, произведённые над ними, приведут к ошибке. Это произойдёт по тому, что числа, записанные в другом коде (отличном от позиционного), подчиняются и иным математическим законам.
Допустим, мы хотим сложить два однобайтовых двоично-десятичных числа 0x95 и 0x76, которые представляют собой запись десятичных чисел 95 и 76 соответственно (в младших полубайтах записано число единиц, в старших - число десятков), и получить сумму 0x171 (7 десятков, 1 единица, установленный флаг переноса C как сотня) представленную также в двоично-десятичном формате. Однако, после выполнения команды add Rd,Rr будет получено число 0x10B (0x0B и установленный флаг переноса C) и это полностью законный результат с точки зрения двоичной арифметики.
У многих микропроцессоров существует специальная команда, которая осуществляет коррекцию результата сложения, если слагаемые были представлены в двоично-десятичном формате. В нашем случае такая команда преобразовала бы сумму 0x10B в 0x171. Однако у AVR-микроконтроллеров такая инструкция, к сожалению, отсутствует. Тем не менее, двоично-десятичную коррекцию можно легко реализовать программным способом.
Использование двоично-десятичной коррекции совместно с вычислительной схемой Горнера позволяет преобразовать двоичные числа в следующей последовательности:
B = (…(bn-1*2 + bn-2)*2 + … + b1)*2 + b0.
К произведению bn-1*2 прибавляем следующий справа двоичный разряд bn-2 и посредством двоично-десятичной коррекции преобразуем двоичную сумму bn-1*2 + bn-2 в двоично-десятичную форму представления. На следующем этапе точно также производится умножение (bn-1*2 + bn-2)*2 и, после прибавления разряда bn-3, сумма (bn-1*2 + bn-2)*2 + bn-3 снова подлежит коррекции и т.д.
Следующая подпрограмма осуществляет преобразование двоичного трёхбайтового числа, лежащего в диапазоне 0…0xFFFFFF, в десятичное (0…16777215). Вместо серии умножений bn-1*2, (bn-1*2 + bn-2)*2, … в нём используется сдвиг накопителя суммы на 1 разряд влево.
; R22:R21:R20:R19:R18 <- R18:R17:R16 ; R22:R21:R20:R19:R18 - двоично-десятичные числа после ; преобразования (R18 - единицы и десятки, R19 - сотни ; и тысячи,…, R22 - миллионы, R23 - десятки миллионов) ; R18:R17:R16 - двоичное преобразуемое число, лежащее ; в диапазоне (0…0xFFFFFF) ; R23,R24 - вспомогательный регистр bin24_dec8: clr R19 ;очищаем вспомогательные регистры clr R20 ;R19,R20,R21,R22 при входе в подпрограмму clr R21 clr R22 ldi R24,24 ;инициализируем счётчик сдвигов bc1: lsl R16 ;производим сдвиг 7-байтового rol R17 ;регистра R22:R21:R20:R19:R18:R17:R16 rol R18 ;при этом происходит умножение bn-1*2 rol R19 ;старшего двоичного разряда, а произведение rol R20 ;попадает в R19 rol R21 rol R22 dec R24 brne PC+2 ret mov R23,R19 ;после этого производится rcall bdec_cor ;двоично-десятичная коррекция накопителя mov R19,R23 ;суммы R22:R21:R20:R19 mov R23,R20 rcall bdec_cor mov R20,R23 mov R23,R21 rcall bdec_cor mov R21,R23 mov R23,R22 rcall bdec_cor mov R22,R23 rjmp bc1 bdec_cor: subi R23,-0x03 ;подпрограмма осуществляет sbrs R23,3 ;двоично-десятичную коррекцию subi R23, 0x03 ;числа в регистре R23 subi R23,-0x30 sbrs R23,7 subi R23,0x30 ret
Перейти к следующей части: Преобразование рефлексного кода в позиционный двоичный
Комментарии (4) | Я собрал (0) | Подписаться
Для добавления Вашей сборки необходима регистрация
BRCC - это переход при С=0