реклама на сайте
подробности

 
 
> Разделение числа на разряды, динамическая индикация
Abell
сообщение Dec 19 2006, 13:43
Сообщение #1


профессиональный дилетант
****

Группа: Участник
Сообщений: 866
Регистрация: 16-03-06
Из: Шебекино - Лысьва - Тюмень
Пользователь №: 15 292



Подскажите, плз, какие алгоритмы вообще существуют для разделения числа на разряды? есть задача, требуется отобразить измеренное значение на семисегментном динамическом дисплее. создал массив по количеству разрядов, в цикле делю исходное число на 10 без остатка, обратно умножаю на 10 и вычитаю из исходного. так все получается, но, может, есть более простые/быстрые пути?


--------------------
Скоро дело сказывается, да не скоро сказка делается, или тише будешь - дальше уедешь...

Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов (1 - 4)
Гвоздик
сообщение Dec 21 2006, 13:39
Сообщение #2


Частый гость
**

Группа: Свой
Сообщений: 153
Регистрация: 2-12-04
Из: Чебоксары
Пользователь №: 1 289



Подходит обычный перевод десятичного числа в двоично-десятичное: циклическое целочисленное деление исходного десятичного на десять, получившийся остаток от деления выносится на сегмент индикатора, начиная с младшего. Может объясняю немного сумбурно, лучше на примерчике покажу:
238 % 10 = 8 - на младший сегмент
23 % 10 = 3 - на средний сегмент
2 % 10 = 0, отсюда выносим сам разряд тогда = 2 - на старший сегмент
А подпрограммку написать тут труда особого, думаю, не составит. Удачи
Go to the top of the page
 
+Quote Post
dxp
сообщение Dec 21 2006, 14:43
Сообщение #3


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(Abell @ Dec 19 2006, 16:43) *
Подскажите, плз, какие алгоритмы вообще существуют для разделения числа на разряды? есть задача, требуется отобразить измеренное значение на семисегментном динамическом дисплее. создал массив по количеству разрядов, в цикле делю исходное число на 10 без остатка, обратно умножаю на 10 и вычитаю из исходного. так все получается, но, может, есть более простые/быстрые пути?

Деление на 10 довольно неэффективно на МК, где нет аппаратной операции деления. Намного эффективнее работает схема на основе представления числа в виде полинома Горнера. Цитата из эхо-конференции ru.embedded (эх, хорошие были времена smile.gif):

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

Абисняю на примере. Имеем дв.код 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е так ли ?


Я на основе этого алгоритма когда-то слепил для себя подпрограмму для MSP430:

Код
bin2BCD16:

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

    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


Это, собственно, код преобразования. Результат получается упаковынный по тетрадам (ниблам). У меня там дальше еще шел код распаковки каждой цифири в отдельный байт, но это к делу уже не относится.

Для AVR есть аналогичная подпрограмма, правда, я ее не писал сам, она идет в какой-то атмеловской аппликухе. Я ее лишь адаптировал для возможности вызова в IAR (под соглашения о вызове подрихтовал). На AVR выходит не так коротко, т.к. он, во-первых, 8-разрядный (а тут 16 бит актуальны), во-вторых, у AVR нет инструкций десятичной коррекции при сложении, а у MSP430 есть. Но принцип везде один и тот же, помедитируйте, разобраться не так сложно.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
umup
сообщение Jan 12 2007, 15:34
Сообщение #4


Местный
***

Группа: Свой
Сообщений: 226
Регистрация: 2-06-06
Пользователь №: 17 720



Есть на С (метод сдвига и десятичной коррекции, возможно,самый быстрый для BCD преобразования).
Описание метода - в книге Титце,Шенк Полупроводниковая схемотехника, стр.320 (http://www.cqham.ru/lib.htm)

Функция bin2bcd32 - преобразование binary -> packed bcd (num_bytes - количество байтов на выходе)

Код
uint32_t bin2bcd32(uint32_t num, uint8_t num_bytes) /**< \brief Convert uint32_t num to packed BCD using num_bytes of number - universal \ingroup ul_math */
{uint32_t ul1=0; /*result*/
uint8_t uc1;
for (uc1=(4-num_bytes);uc1;uc1--) num<<=8; /*adjust input bytes*/
for (uc1=(num_bytes<<3);uc1;uc1--) /*bit shift loop*/
{uint8_t uc2,uc3;
  /*BCD nibbles correction*/
  ul1+=0x33333333;
  for (uc3=4;uc3;uc3--)
  {uc2=(uint8_t)(ul1>>24);
   if (!(uc2&0x08)) uc2-=0x03;
   if (!(uc2&0x80)) uc2-=0x30;
   ul1=ul1<<8; ul1|=uc2;
  }
  /*shift next bit of input and result*/
  ul1<<=1;
  if ((num>>24)&0x80) ul1|=1;
  num<<=1;
}
return(ul1);
}


Сообщение отредактировал umup - Jan 12 2007, 15:47
Go to the top of the page
 
+Quote Post
Alex03
сообщение Jan 14 2007, 18:59
Сообщение #5


Местный
***

Группа: Свой
Сообщений: 359
Регистрация: 9-12-05
Пользователь №: 12 034



Я вот так это реализовывал:
Код
uint64_t  bin2bcdU64(uint32_t n)
{
    int i;
    uint64_t ll;
    uint64_t ull = 0ULL;

    for(i=0;;i++)
    {
        ull = (ull<<1) | (n>>31);
        n <<= 1;

        if(i==31)
            break;

        ll = ( (ull>>3) | ((ull>>2) & ((ull>>1)|ull) ) ) & 0x1111111111ULL;
        ull += ll | (ll<<1);
    }
    return ull;
}

т.е. Всё 32-х разрядное число в 64-х разрядное, в котором 10 значащих двоичнодесятичных разряда.
Если диапазон входных значений меньше то легко можно упростить/ускорить сократив разрядность переменных и укоротив цикл.

ЗЫ А всётаки кое чё на АСМах красивей! smile.gif
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 20th July 2025 - 21:40
Рейтинг@Mail.ru


Страница сгенерированна за 0.01367 секунд с 7
ELECTRONIX ©2004-2016