Ассемблер (ASM) для AVR в вопросах и ответах
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Ассемблер (ASM) для AVR в вопросах и ответах
Ну.. на побитовое И он тоже не особо был похож 
- Реклама
-
sibiryak69
- Первый раз сказал Мяу!
- Сообщения: 24
- Зарегистрирован: Вс июн 19, 2016 06:31:18
Re: Ассемблер (ASM) для AVR в вопросах и ответах
Всем спасибо за ответы, но все таки хотелось бы задать еще несколько уточняющих вопросов если позволите.
это понятно, что биты USIWMO, USICS1, USICLK и USITC принадлежат регистру USICR, но если я правильно понял в каждом из этих выражений 1<<USIWMO, 1<<USICS1, 1<<USICLK и 1<<USITC единица или или сдвинется на один разряд в лево или нет (в зависимости от установок битов USIWMO, USICS1, USICLK и USITC) затем между выражениями произведена операция побитового "или" и в результате константа может принять одно из трех значений 1, 2 или 3. (Для чего попытаюсь разобраться).
на сколько я знаю в ассемблере AVR нет таких операторов "<<" и "|" там они пишутся по другому и компилятор эти начертания по логике не должен понять (или я не прав??)
COKPOWEHEU пишет "Полностью аналогичен x = x*2^y не совсем понятно аналогичен чему. Насколько я понимаю х умножается на 2, а затем проводится "исключающее или" между произведением и "у" , но это опять операторы СИ
Спасибо
это понятно, что биты USIWMO, USICS1, USICLK и USITC принадлежат регистру USICR, но если я правильно понял в каждом из этих выражений 1<<USIWMO, 1<<USICS1, 1<<USICLK и 1<<USITC единица или или сдвинется на один разряд в лево или нет (в зависимости от установок битов USIWMO, USICS1, USICLK и USITC) затем между выражениями произведена операция побитового "или" и в результате константа может принять одно из трех значений 1, 2 или 3. (Для чего попытаюсь разобраться).
на сколько я знаю в ассемблере AVR нет таких операторов "<<" и "|" там они пишутся по другому и компилятор эти начертания по логике не должен понять (или я не прав??)
COKPOWEHEU пишет "Полностью аналогичен x = x*2^y не совсем понятно аналогичен чему. Насколько я понимаю х умножается на 2, а затем проводится "исключающее или" между произведением и "у" , но это опять операторы СИ
Спасибо
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Ассемблер (ASM) для AVR в вопросах и ответах
Всё просто. Например, для ATtiny2313 (для номеров битов смотрим либо даташит, либо соответствующий инклюд:
Все записи полностью идентичны, но первая гораздо понятнее, чем "магическое" число в последней.
Код: Выделить всё
ldi r16, (1<<USIWMO)|(1<<USICS1)|(1<<USICLK)|(1<<USITC)
ldi r16, (1<<4) |(1<<3) |(1<<1) |(1<<0)
ldi r16, 0b00010000 |0b00001000 |0b00000010 |0b00000001
ldi r16, 0b00011011- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18544
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: Ассемблер (ASM) для AVR в вопросах и ответах
ассемблер состоит из двух частей: мнемокодов команд и операций ассемблера (терминология моя). мнемокод - это символьный аналог команды ALU, например, mov, ldi или rol. разумеется, последний мнемокод означает "сдвиг влево", т.к. вроде бы является аналогом оператора Си <<, и это на самом деле так. но есть еще операция языка ассемблера <<, которая означает ровно то же самое, но выполняется ассемблером на этапе компиляции. то есть не ALU микроконтроллера делает этот сдвиг, а сам ассемблер все двигает, подставляя в команду уже готовый результат этих сдвигов.sibiryak69 писал(а):на сколько я знаю в ассемблере AVR нет таких операторов "<<" и "|" там они пишутся по другому и компилятор эти начертания по логике не должен понять (или я не прав??)
улавливаете разницу?
rol r3, 4 в этом случае полностью эквивалентно rol r3, 1<<2, т.к. 1<<2 это и будет 4. таким образом, во время написания программы вы пользуетесь удобными вам константами, компилятор ассемблера делает необходимые вычисления сам, и подставляет в мнемокоды уже готовые числа.
итак, разница в операторе << языка Си и ассемблера в том, что в Си этот оператор может выполняться либо на этапе компиляции (макросы), либо на этапе исполненияя программы, а в ассемблере этот оператор всегда выполняется на этапе компиляции. и, естественно, оба операнда этого оператора должны быть константами, иначе компилятор не сможет выполнить эту работу - попробуйте написать что-то типа ldi r17, 1<<r6 - получите ошибку компиляции.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
Re: Ассемблер (ASM) для AVR в вопросах и ответах
У АВРок системой команд официально не предусматривается прямое указание в команде количества сдвигов в случае с командами циклического сдвига / вращения (ROL\ROR и подобное).
Это преимущество только за системой команд 8088/8086 и выше (и то, там еще регистр-счетчик вроде задействуется, ежли шклерозь не изменяет...).
Конструкция rol rn,x скорее всего должна быть заменена препроцессором на цепочку из х команд rol rn, воспринимаемых самим МК... (если вообще будет пропущена компилятором - сам так "заворачивать" не пробовал)...

Это преимущество только за системой команд 8088/8086 и выше (и то, там еще регистр-счетчик вроде задействуется, ежли шклерозь не изменяет...).
Конструкция rol rn,x скорее всего должна быть заменена препроцессором на цепочку из х команд rol rn, воспринимаемых самим МК... (если вообще будет пропущена компилятором - сам так "заворачивать" не пробовал)...
- Реклама
- COKPOWEHEU
- Говорящий с текстолитом
- Сообщения: 1525
- Зарегистрирован: Чт июн 10, 2010 20:11:19
Re: Ассемблер (ASM) для AVR в вопросах и ответах
[uquote="sibiryak69",url="/forum/viewtopic.php?p=3171415#p3171415"]COKPOWEHEU пишет "Полностью аналогичен x = x*2^y не совсем понятно аналогичен чему. Насколько я понимаю х умножается на 2, а затем проводится "исключающее или" между произведением и "у" , но это опять операторы СИ[/uquote]^ в смысле возведение в степень а не XOR.
это разворачивается последовательно в
Точно также Си-подобные операторы |, &, << и т.п. относятся к препроцессору и выполняются перед запуском компилятора, которому в результате достаются готовые вычисленные константы и адреса.
Да, что-то я там совсем странное написал... хотя бы исправленная версия нормально?WiseLord писал(а):Ну.. на побитовое И он тоже не особо был похож
ARV уже ответил, но продублирую. Сборка программы состоит из 2-х этапов: препроцессирование и компиляция (вообще-то есть еще линковка, но родной AVR ассемблер этого напрямую не умеет). На первом этапе препроцессор анализирует текст программы, не глядя на синтаксис целевого языка и обрабатывая только свои конструкции. Например, подставляет макросы прямо в текст программы, заменяет .def и .equ на соответствующие значения, подставляет вместо .include содержимое файла, и так далее. Примерно таким образом:sibiryak69 писал(а):на сколько я знаю в ассемблере AVR нет таких операторов "<<" и "|" там они пишутся по другому и компилятор эти начертания по логике не должен понять (или я не прав??)
Код: Выделить всё
.def temp=r16
.macro outi
ldi temp, @1
out @0, temp
.endm
outi PORTB, 1Код: Выделить всё
ldi temp, (1<<2)
out PORTB,tempКод: Выделить всё
ldi r16,0b00000100;основание системы счисления я оставил наиболее наглядным, компилятору-то без разницы
out 0x18, r16-
sibiryak69
- Первый раз сказал Мяу!
- Сообщения: 24
- Зарегистрирован: Вс июн 19, 2016 06:31:18
Re: Ассемблер (ASM) для AVR в вопросах и ответах
[uquote="WiseLord",url="/forum/viewtopic.php?p=3171428#p3171428"]Всё просто. Например, для ATtiny2313 (для номеров битов смотрим либо даташит, либо соответствующий инклюд:
Все записи полностью идентичны, но первая гораздо понятнее, чем "магическое" число в последней.[/uquote]
не совсем понятно для чего в выше приведенном выражении использовать название разрядов регистра управления и что под этими названиями в данном случае подразумевается или номер разряда или содержимое разряда. Если номер разряда, то смысл в написании названия пропадает, и для меня более понятной будет последняя запись (все как говорится на месте, в регистр записывается конкретная константа) Если под названием разряда подразумевается его содержимое то это уже не константа.
Добавлено after 13 minutes 38 seconds:
[uquote="ARV",url="/forum/viewtopic.php?p=3171459#p3171459"]
улавливаете разницу?
rol r3, 4 в этом случае полностью эквивалентно rol r3, 1<<2, т.к. 1<<2 это и будет 4. таким образом, во время написания программы вы пользуетесь удобными вам константами, компилятор ассемблера делает необходимые вычисления сам, и подставляет в мнемокоды уже готовые числа.
итак, разница в операторе << языка Си и ассемблера в том, что в Си этот оператор может выполняться либо на этапе компиляции (макросы), либо на этапе исполненияя программы, а в ассемблере этот оператор всегда выполняется на этапе компиляции. и, естественно, оба операнда этого оператора должны быть константами, иначе компилятор не сможет выполнить эту работу - попробуйте написать что-то типа ldi r17, 1<<r6 - получите ошибку компиляции.[/uquote]
Насколько я знаю в ассемблере есть два вида команд.
1 Как выше указал "ARV" мнемокод. Мнемокод по терминологии называется оператором
2 Второй вид команд это "дерективы". как выше указал ARV "дерективы" выполняются компилятором (как в языках программирования высокого уровня тот же "СИ") , примеры приводить не буду "COKPOWEHEU" привел хороший пример
но я такой команды "дерективы" как << в AVR не видел
Если я не прав пожалуйста растолкуйте
Код: Выделить всё
ldi r16, (1<<USIWMO)|(1<<USICS1)|(1<<USICLK)|(1<<USITC)
ldi r16, (1<<4) |(1<<3) |(1<<1) |(1<<0)
ldi r16, 0b00010000 |0b00001000 |0b00000010 |0b00000001
ldi r16, 0b00011011не совсем понятно для чего в выше приведенном выражении использовать название разрядов регистра управления и что под этими названиями в данном случае подразумевается или номер разряда или содержимое разряда. Если номер разряда, то смысл в написании названия пропадает, и для меня более понятной будет последняя запись (все как говорится на месте, в регистр записывается конкретная константа) Если под названием разряда подразумевается его содержимое то это уже не константа.
Добавлено after 13 minutes 38 seconds:
[uquote="ARV",url="/forum/viewtopic.php?p=3171459#p3171459"]
ассемблер состоит из двух частей: мнемокодов команд и операций ассемблера (терминология моя). мнемокод - это символьный аналог команды ALU, например, mov, ldi или rol. разумеется, последний мнемокод означает "сдвиг влево", т.к. вроде бы является аналогом оператора Си <<, и это на самом деле так. но есть еще операция языка ассемблера <<, которая означает ровно то же самое, но выполняется ассемблером на этапе компиляции. то есть не ALU микроконтроллера делает этот сдвиг, а сам ассемблер все двигает, подставляя в команду уже готовый результат этих сдвигов.sibiryak69 писал(а):на сколько я знаю в ассемблере AVR нет таких операторов "<<" и "|" там они пишутся по другому и компилятор эти начертания по логике не должен понять (или я не прав??)
улавливаете разницу?
rol r3, 4 в этом случае полностью эквивалентно rol r3, 1<<2, т.к. 1<<2 это и будет 4. таким образом, во время написания программы вы пользуетесь удобными вам константами, компилятор ассемблера делает необходимые вычисления сам, и подставляет в мнемокоды уже готовые числа.
итак, разница в операторе << языка Си и ассемблера в том, что в Си этот оператор может выполняться либо на этапе компиляции (макросы), либо на этапе исполненияя программы, а в ассемблере этот оператор всегда выполняется на этапе компиляции. и, естественно, оба операнда этого оператора должны быть константами, иначе компилятор не сможет выполнить эту работу - попробуйте написать что-то типа ldi r17, 1<<r6 - получите ошибку компиляции.[/uquote]
Насколько я знаю в ассемблере есть два вида команд.
1 Как выше указал "ARV" мнемокод. Мнемокод по терминологии называется оператором
2 Второй вид команд это "дерективы". как выше указал ARV "дерективы" выполняются компилятором (как в языках программирования высокого уровня тот же "СИ") , примеры приводить не буду "COKPOWEHEU" привел хороший пример
но я такой команды "дерективы" как << в AVR не видел
Если я не прав пожалуйста растолкуйте
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18544
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: Ассемблер (ASM) для AVR в вопросах и ответах
теперь видели. еще и >> есть тоже. читайте документацию на avrassembler2sibiryak69 писал(а):но я такой команды "дерективы" как << в AVR не видел
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
Re: Ассемблер (ASM) для AVR в вопросах и ответах
Всем доброго времени суток.
Возможно немного не в тему, но..
Возникла у меня недавно необходимость деления целых чисел. Исшарил много интернетов, но внятного, а тем более однозначного куска кода или алгоритма не нашел (может просто плохо искал, не спорю, но искал именно на Ассемблер). Так вот, не найдя ничего готового сел изобретать велосипед. Привожу два своих варианта алгоритмов на общественный суд, ну и может кому пригодится. (тема по конкретно этому вопросу закрыта и не доведена до лог завершения).
Итак:
1й вариант короткий по коду, но при большой разнице делимого и делителя занимает много проц. времени:
lds Temp1,Time ;загружаем делимое в переменную
val_1:
cpi Temp1,10 ;сравнивем делимое с делителем
brlo val_11 ;если меньше - к выходу
subi Temp1,10 ;иначе вичетаем из делимого делитель
inc count ;считаем кол-во циклов
rjmp val_1 ;повторяем пока делимое не станет меньше делителя
val_11:
sts Digit,Temp1 ;выгружаем остаток
sts Digit+1,count ;выгружаем частное
clr count ;очищаем счетчик
exit_val:
ret
2й занимает больше места, но выполняется немного быстрей и более стабилен по времени + правильней с точки зрения двоичной математики:
; .def dividend=r20 ;делимое
; .def divider=r21 ;делитель
; .def quotient=r22 ;частное
Divisn:
ldi count,8 ;инициализируем счетчик (1)
div:
rol r20 ;2 сдвига влево через перенос. Сначала сдвигаем делимое, занося в бит преноса старший (1)
rol r19 ;бит делимого, затем вносим бит переноса в вспомогательный регистр,(1)
;где собственно и происходит деление
cp r19,r21 ;сравниваем полученый результат в вспом регистре с делителем (1)
brlo div0 ;если меньше - переходим к установке ноля в рег результата (1) (2 - если условия соблюд)
rjmp div1 ;иначе к установке единицы туда же (2)
div_sub:
sub r19,r21 ;вычетаем из вспом регистра делитель (1)
rjmp div ;возвращаемся к началу (2)
div0:
clc ;сбросить бит переноса (1)
rol r22 ;делаем сдвиг влево с переносом (1)
dec count ;минус 1 цикл счетчика (1)
breq exit_div ;если прошли 8 циклов - на выход (1) (2 - если условия соблюд)
rjmp div ;иначе повторим сначала (2)
div1:
sec ;Аналогично, с одним НО (1)
rol r22 ;(1)
dec count ;(1)
breq exit_div ;(1) (2 - если условия соблюд)
rjmp div_sub ;возврат к вычетанию (2)
exit_div:
;при любых значениях делимого и делителя весь процесс
;занимает 8 циклов
;(в скобках указано кол-во циклов команды)
ret ;результат помещается в r22
;остаток в r19
Ну вот, высказался. Вроде легче стало 
Возможно немного не в тему, но..
Возникла у меня недавно необходимость деления целых чисел. Исшарил много интернетов, но внятного, а тем более однозначного куска кода или алгоритма не нашел (может просто плохо искал, не спорю, но искал именно на Ассемблер). Так вот, не найдя ничего готового сел изобретать велосипед. Привожу два своих варианта алгоритмов на общественный суд, ну и может кому пригодится. (тема по конкретно этому вопросу закрыта и не доведена до лог завершения).
Итак:
1й вариант короткий по коду, но при большой разнице делимого и делителя занимает много проц. времени:
Спойлер
Time_val:lds Temp1,Time ;загружаем делимое в переменную
val_1:
cpi Temp1,10 ;сравнивем делимое с делителем
brlo val_11 ;если меньше - к выходу
subi Temp1,10 ;иначе вичетаем из делимого делитель
inc count ;считаем кол-во циклов
rjmp val_1 ;повторяем пока делимое не станет меньше делителя
val_11:
sts Digit,Temp1 ;выгружаем остаток
sts Digit+1,count ;выгружаем частное
clr count ;очищаем счетчик
exit_val:
ret
Спойлер
; .def division=r19 ;вспом регистр для арифметических действий; .def dividend=r20 ;делимое
; .def divider=r21 ;делитель
; .def quotient=r22 ;частное
Divisn:
ldi count,8 ;инициализируем счетчик (1)
div:
rol r20 ;2 сдвига влево через перенос. Сначала сдвигаем делимое, занося в бит преноса старший (1)
rol r19 ;бит делимого, затем вносим бит переноса в вспомогательный регистр,(1)
;где собственно и происходит деление
cp r19,r21 ;сравниваем полученый результат в вспом регистре с делителем (1)
brlo div0 ;если меньше - переходим к установке ноля в рег результата (1) (2 - если условия соблюд)
rjmp div1 ;иначе к установке единицы туда же (2)
div_sub:
sub r19,r21 ;вычетаем из вспом регистра делитель (1)
rjmp div ;возвращаемся к началу (2)
div0:
clc ;сбросить бит переноса (1)
rol r22 ;делаем сдвиг влево с переносом (1)
dec count ;минус 1 цикл счетчика (1)
breq exit_div ;если прошли 8 циклов - на выход (1) (2 - если условия соблюд)
rjmp div ;иначе повторим сначала (2)
div1:
sec ;Аналогично, с одним НО (1)
rol r22 ;(1)
dec count ;(1)
breq exit_div ;(1) (2 - если условия соблюд)
rjmp div_sub ;возврат к вычетанию (2)
exit_div:
;при любых значениях делимого и делителя весь процесс
;занимает 8 циклов
;(в скобках указано кол-во циклов команды)
ret ;результат помещается в r22
;остаток в r19
Если я чего-то не знаю, это не говорит о моем невежестве, а только о том, что раньше этот вопрос лежал вне сферы моих интересов.
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Ассемблер (ASM) для AVR в вопросах и ответах
[uquote="sibiryak69",url="/forum/viewtopic.php?p=3173454#p3173454"][uquote="WiseLord",url="/forum/viewtopic.php?p=3171428#p3171428"]Всё просто. Например, для ATtiny2313 (для номеров битов смотрим либо даташит, либо соответствующий инклюд:
Все записи полностью идентичны, но первая гораздо понятнее, чем "магическое" число в последней.[/uquote]не совсем понятно для чего в выше приведенном выражении использовать название разрядов регистра управления и что под этими названиями в данном случае подразумевается или номер разряда или содержимое разряда. Если номер разряда, то смысл в написании названия пропадает, и для меня более понятной будет последняя запись (все как говорится на месте, в регистр записывается конкретная константа) Если под названием разряда подразумевается его содержимое то это уже не константа.[/uquote]
Ещё раз - это номера битов, ровно как они указаны в даташите. И при использовании первого варианта сразу понятно, что в регистр записывается байт, у которого установлены эти биты.
Последний вариант - магическое число, непонятно откуда взявшееся в программе. Понять, почему использовано именно это число невозможно, не заглядывая дальше по коду. Нужно обязательно смотреть, в какой регистр этот r16 будет записан и лезть в даташит смотреть биты этого регистра.
Если же писать по первому варианту, то с первого взгляда на имена битов становится понятно, что они относятся к одному из регистров USI.
Далее, при переносе кода на другой МК все эти магические числа испортят немало нервных клеток, так как нет гарантии, что в новом МК эти биты не поменяли свою позицию в регистре. А если использовать имена - эта проблема практически исчезает.
Микроконтроллеру всё равно - в обоих случаях в регистр записывается конкретная константа и бинарный код будет одинаков. Другое дело, что в первом случае эту константу вычисляет препроцессор/компилятор, а не сам программист.
Часто возникает необходимость деления на некоторую константу. Обычно это 10 (развёртка числа в строку для индикации). В таком случае (делитель - константа) удобен следующий принцип.
Скажем, нужно быстро разделить некоторое 8-битное (0..255) число на 10. Как правило, обычные алгоритмы сначала выясняют, что число больше 100 но меньше тысячи, вычитают (дважды) сотню - получают число 2, затем пять раз вычитают 10 (5) и остаётся ещё 5 единиц. Довольно долго.
Есть немного другой подход. Разделить на 10 - это то же самое, что и 1) умножить на x и 2) разделить на 10x. Умножать многие МК умеют аппаратно (да и программно это легче чем делить), а вот второй пункт можно обойти хитростью - сделать так, чтобы 10x было близко (чуть больше) к некоторой степени двойки. Для константы 10 наиболее удобно число 2050 (чуть больше 2048). Получаем:
N / 10 = N * 205 / 2050 ~= N * 205 / 2048 = (N * 205) >> 11;
Да, при делении на 2050 получится число немного меньшее, чем при делении на 2048, но для однобайтных чисел от 0 до 255 результат (за счёт отбрасывания при целочисленном делении) будет одинаковый.
А умножить байт на 205, а потом сдвинуть вправо на 11 - это гораздо быстрее ряда вычитаний, да и выполняется это за константное время.
Код: Выделить всё
ldi r16, (1<<USIWMO)|(1<<USICS1)|(1<<USICLK)|(1<<USITC)
ldi r16, 0b00011011Ещё раз - это номера битов, ровно как они указаны в даташите. И при использовании первого варианта сразу понятно, что в регистр записывается байт, у которого установлены эти биты.
Последний вариант - магическое число, непонятно откуда взявшееся в программе. Понять, почему использовано именно это число невозможно, не заглядывая дальше по коду. Нужно обязательно смотреть, в какой регистр этот r16 будет записан и лезть в даташит смотреть биты этого регистра.
Если же писать по первому варианту, то с первого взгляда на имена битов становится понятно, что они относятся к одному из регистров USI.
Далее, при переносе кода на другой МК все эти магические числа испортят немало нервных клеток, так как нет гарантии, что в новом МК эти биты не поменяли свою позицию в регистре. А если использовать имена - эта проблема практически исчезает.
Микроконтроллеру всё равно - в обоих случаях в регистр записывается конкретная константа и бинарный код будет одинаков. Другое дело, что в первом случае эту константу вычисляет препроцессор/компилятор, а не сам программист.
Судя по коду, Вы реализовывали деление любого числа на любое число, поэтому получилось что-то довольно громоздкое.Jetetex писал(а):Возникла у меня недавно необходимость деления целых чисел
Часто возникает необходимость деления на некоторую константу. Обычно это 10 (развёртка числа в строку для индикации). В таком случае (делитель - константа) удобен следующий принцип.
Скажем, нужно быстро разделить некоторое 8-битное (0..255) число на 10. Как правило, обычные алгоритмы сначала выясняют, что число больше 100 но меньше тысячи, вычитают (дважды) сотню - получают число 2, затем пять раз вычитают 10 (5) и остаётся ещё 5 единиц. Довольно долго.
Есть немного другой подход. Разделить на 10 - это то же самое, что и 1) умножить на x и 2) разделить на 10x. Умножать многие МК умеют аппаратно (да и программно это легче чем делить), а вот второй пункт можно обойти хитростью - сделать так, чтобы 10x было близко (чуть больше) к некоторой степени двойки. Для константы 10 наиболее удобно число 2050 (чуть больше 2048). Получаем:
N / 10 = N * 205 / 2050 ~= N * 205 / 2048 = (N * 205) >> 11;
Да, при делении на 2050 получится число немного меньшее, чем при делении на 2048, но для однобайтных чисел от 0 до 255 результат (за счёт отбрасывания при целочисленном делении) будет одинаковый.
А умножить байт на 205, а потом сдвинуть вправо на 11 - это гораздо быстрее ряда вычитаний, да и выполняется это за константное время.
Re: Ассемблер (ASM) для AVR в вопросах и ответах
По мне, проще как здесь
Re: Ассемблер (ASM) для AVR в вопросах и ответах
Если правильно понял два последних алгоритма, то в них пренебрегаем остатком после деления, принимая во внимание только целую часть (может конечно и ошибаюсь). В некоторых случаях это критично. К примеру в моем случае нужно сначала 1440 (2 рег) / 24 получаем на выходе 2 рег ответа (целое и остаток), после этого каждый из них разделить на 10 (привести в знаки индикатора). То есть остаток имеет довольно важное значение.
Если я чего-то не знаю, это не говорит о моем невежестве, а только о том, что раньше этот вопрос лежал вне сферы моих интересов.
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Ассемблер (ASM) для AVR в вопросах и ответах
Ну, так никто не мешает после получения результата (целого частного) быстро вычислить и остаток.
N / 24 = X, в остатке Y. В вашем случае Вы путём долгих вычислений получаете сразу оба числа. Но ведь если X получен быстрым способом, то уже не проблема так же быстро получить: Y = N - 24*X;
N / 24 = X, в остатке Y. В вашем случае Вы путём долгих вычислений получаете сразу оба числа. Но ведь если X получен быстрым способом, то уже не проблема так же быстро получить: Y = N - 24*X;
-
sibiryak69
- Первый раз сказал Мяу!
- Сообщения: 24
- Зарегистрирован: Вс июн 19, 2016 06:31:18
Re: Ассемблер (ASM) для AVR в вопросах и ответах
WiseLord спасибо за объяснение. Если я правильно понял, данный вид записи (ldi r16, (1<<USIWMO)|(1<<USICS1)|(1<<USICLK)|(1<<USITC)) универсален тем, что в разных МК биты с одним названием могут находиться в разных разрядах, и при переносе с одного МК на другой, компилятор сам вычислит число необходимое для выставления нужных разрядов, а программисту не надо парится 
-
Demiurg
- Это не хвост, это антенна
- Сообщения: 1480
- Зарегистрирован: Ср июн 25, 2008 15:19:44
- Контактная информация:
Re: Ассемблер (ASM) для AVR в вопросах и ответах
Не вычислит, а согласно заголовочному файлу соответствующего МК.
- COKPOWEHEU
- Говорящий с текстолитом
- Сообщения: 1525
- Зарегистрирован: Чт июн 10, 2010 20:11:19
Re: Ассемблер (ASM) для AVR в вопросах и ответах
Важнее другое. При взгляде на такую запись сразу понятно что хотел сделать программист.
Сравните эти две записи: какую проще понять?
"Любой дурак может написать программу, понятную машине. Настоящие программисты пишут программы, понятные людям" (с) Мартин Фаулер
Сравните эти две записи: какую проще понять?
Код: Выделить всё
ldi temp, (1<<OCIE1A)
out TIMSK, tempКод: Выделить всё
ldi r16, 16
out 0x39, r16Re: Ассемблер (ASM) для AVR в вопросах и ответах
В обработчике запустили таймер или сделали отсечку уже запущенного таймера. Ждете отпускания кнопки и в обработчике сделали следующую отсечку. Разница покажет длительность нажатия на кнопку.
-
Demiurg
- Это не хвост, это антенна
- Сообщения: 1480
- Зарегистрирован: Ср июн 25, 2008 15:19:44
- Контактная информация:
Re:
[uquote="radio-fan",url="/forum/viewtopic.php?p=3180716#p3180716"]Здравствуйте, начал изучать ассемблер AVR. Интересует такой момент, как с помощью внешнего прерывания улавливать длинное и короткое нажатие на кнопку?[/uquote]
1 - Подключение кнопок к внешнему прерыванию требуется только в единственном случае - если устройству требуется энергосбережение.
2 - Кнопки - человеко-интерфейс. Это значит, что вам не нужна реакция в нано, микро и даже миллисекунды.
3 - У кнопок есть дребезг контактов (спросить у гугла).
Есть цикл статей Татарчевского. Там отлично расписано, как сделать опрос кнопок. Пусть си вас не смущает. Главное понять алгоритм.
Добавлено after 1 minute 19 seconds:
Re: Ассемблер (ASM) для AVR в вопросах и ответах
[uquote="akl",url="/forum/viewtopic.php?p=3180822#p3180822"]В обработчике запустили таймер или сделали отсечку уже запущенного таймера. Ждете отпускания кнопки и в обработчике сделали следующую отсечку. Разница покажет длительность нажатия на кнопку.[/uquote]
Пусть он сразу ознакомится, что такое программные таймеры. И автоматное программирование.
1 - Подключение кнопок к внешнему прерыванию требуется только в единственном случае - если устройству требуется энергосбережение.
2 - Кнопки - человеко-интерфейс. Это значит, что вам не нужна реакция в нано, микро и даже миллисекунды.
3 - У кнопок есть дребезг контактов (спросить у гугла).
Есть цикл статей Татарчевского. Там отлично расписано, как сделать опрос кнопок. Пусть си вас не смущает. Главное понять алгоритм.
Добавлено after 1 minute 19 seconds:
Re: Ассемблер (ASM) для AVR в вопросах и ответах
[uquote="akl",url="/forum/viewtopic.php?p=3180822#p3180822"]В обработчике запустили таймер или сделали отсечку уже запущенного таймера. Ждете отпускания кнопки и в обработчике сделали следующую отсечку. Разница покажет длительность нажатия на кнопку.[/uquote]
Пусть он сразу ознакомится, что такое программные таймеры. И автоматное программирование.
Re:
Зачем уводить от конкретно заданного вопроса
[uquote="radio-fan",url="/forum/viewtopic.php?p=3180716#p3180716"]... как с помощью внешнего прерывания улавливать длинное и короткое нажатие на кнопку?[/uquote]
может radio-fan вырос из программных таймеров и переходит на более высокий уровень, задействуя аппаратную периферию и прерывания от оной для опроса кнопок в фоновом режиме.
[uquote="radio-fan",url="/forum/viewtopic.php?p=3180716#p3180716"]... как с помощью внешнего прерывания улавливать длинное и короткое нажатие на кнопку?[/uquote]
может radio-fan вырос из программных таймеров и переходит на более высокий уровень, задействуя аппаратную периферию и прерывания от оной для опроса кнопок в фоновом режиме.


