Приветствую Вас ГостьСуббота, 30.11.2024, 07:24

Микроконтроллеры для всех


Каталог статей

Главная » Статьи » Мои статьи

Операция деления на AVR

  Как известно у AVR микроконтроллеров отсутствует узел аппаратного делителя. Это тот узел , который позволяет организовать операцию деления над байтами без особых программных затрат. Обычно этот узел имеется на борту всех сигнальных процессоров, поскольку данная операция необходима при обработки сигналов. Еще встречается аппаратный делитель у МК 51 и у других микроконтроллеров. У AVR микроконтроллеров компания ATMEL игнорирует этот узел, и балует нас только арифметическим или/и логическим сложением, вычитанием, умножением. 

  Чтобы поделить одно двухбайтное число на однобайтное в таких микроконтроллерах потребуется от 1 до 4 тактов. Это ничего по сравнению с организацией деления в МК AVR. У меня на процедуру деления в формате 0xAAAA / 0xAA = 0xAAАА уходит под 250 тактов. Ну для неплохой точности и малой погрешности быстрее никак не получается. Может вы что-то быстрее придумаете и выкладуйте. 

  Для тех кто работает с АВРками и нуждается в этой операции привожу исходник.

Формат: 0xAAAA / 0xAA = 0xAAАА (то есть 2 байта делим на один, получаем два байта). Запись делимого и делителя производится в тексте программы, а результат (частное) отображается на пинах порта А и С.

Текст программы.

.include "m8535def.inc" ; подключаем библиотеку ATmega8535
.list
.DEF rd1l = R0 ; LSB 16-bit-number to be divided
.DEF rd1h = R1 ; MSB 16-bit-number to be divided
.DEF rd1u = R2 ; interim register
.DEF rd2 = R3 ; 8-bit-number to divide with
.DEF rel = R4 ; LSB result
.DEF reh = R5 ; MSB result
.DEF rmp = R16; multipurpose register for loading
.DEF temp = R17
.CSEG ; программный код расположется в сегменте памяти программ
.ORG 0x0000 ; процессор стартует с нулевого адреса, а дальше пойдут вектора прерывания
RJMP Reset ; прерывания по сбросу. Прыгаем на метку Reset

;================ТАБЛИЦА ВЕКТОРОВ ПРЕРЫВАНИЯ================
.org INT0addr ; External Interrupt 0
reti
.org INT1addr ; External Interrupt 1
reti
.org OC2addr ; Timer/Counter2 Compare Match
reti
.org OVF2addr ; Timer/Counter2 Overflow
reti
.org ICP1addr ; Timer/Counter1 Capture Event
reti
.org OC1Aaddr ; Timer/Counter1 Compare Match A
reti
.org OC1Baddr ; Timer/Counter1 Compare Match B
reti
.org OVF1addr ; Timer/Counter1 Overflow
reti
.org OVF0addr ; Timer/Counter0 Overflow
reti
.org SPIaddr ; SPI Serial Transfer Complete
reti
.org URXCaddr ; USART, RX Complete
reti
.org UDREaddr ; USART Data Register Empty
reti
.org UTXCaddr ; USART, TX Complete
reti
.org ADCCaddr ; ADC Conversion Complete
reti
.org ERDYaddr ; EEPROM Ready
reti
.org ACIaddr ; Analog Comparator
reti
.org TWIaddr ; Two-wire Serial Interface
reti
.org INT2addr ; External Interrupt Request 2
reti
.org OC0addr ; TimerCounter0 Compare Match
reti
.org SPMRaddr ; Store Program Memory Read
reti
.org INT_VECTORS_SIZE ; size in words
reti

;================ НАЧАЛО ИНИЦИАЛИЗАЦИИ ПЕРЕФЕРИИ=================
Reset:
  ldi temp,high(RAMEND) ; инициализация стека
  out SPH,temp
  ldi temp,low(RAMEND)
  out SPL,temp
  ldi temp,0xff
  out DDRC,temp
  out DDRA,temp


start:
  ldi rmp,0b10000000 ; делимое (старший)
  mov rd1h,rmp ;--------------
  ldi rmp,0b00001011; делимое (младший)
  mov rd1l,rmp ;--------------
  ldi rmp,0b00000101 ;делитель
  mov rd2,rmp ;-------------

div8:
  clr rd1u ; clear interim register
  clr reh ; clear result (the result registers
  clr rel ; are also used to count to 16 for the
  inc rel ; division steps, is set to 1 at start)

div8a:
  clc ; clear carry-bit
  rol rd1l ; rotate the next-upper bit of the number
  rol rd1h ; to the interim register (multiply by 2)
  rol rd1u
  brcs div8b ; a one has rolled left, so subtract
  cp rd1u,rd2 ; Division result 1 or 0?
  brcs div8c ; jump over subtraction, if smaller

div8b:
  sub rd1u,rd2; subtract number to divide with
  sec ; set carry-bit, result is a 1
  rjmp div8d ; jump to shift of the result bit
div8c:
  clc ; clear carry-bit, resulting bit is a 0

div8d:
  rol rel ; rotate carry-bit into result registers
  rol reh
  brcc div8a ; as long as zero rotate out of the result
; registers: go on with the division loop
; End of the division reached
stop:
  out portC,rel ;а частное выводим сюда
  out portA,reh ;и сюда
  rjmp stop ; endless loop

Категория: Мои статьи | Добавил: Alex_Sky (27.03.2010)
Просмотров: 10710 | Комментарии: 2 | Теги: Деление, AVR, деление на микроконтроллере, арифметика на МК, программа делителя, Делитель | Рейтинг: 3.5/2
Всего комментариев: 2
2 Alex_Sky  
0
Рад , что пригодилось

1 Дима  
0
Попробовал класно! Работает. Завтра применю на работе. Как раз искал именно такую программу делилку.

Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Поиск
Категории раздела
Мои статьи [19]
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0
Форма входа
Друзья сайта
  • Yourdevice