Всем спасибо за ответы, но все таки хотелось бы задать еще несколько уточняющих вопросов если позволите. это понятно, что биты 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, а затем проводится "исключающее или" между произведением и "у" , но это опять операторы СИ Спасибо
на сколько я знаю в ассемблере AVR нет таких операторов "<<" и "|" там они пишутся по другому и компилятор эти начертания по логике не должен понять (или я не прав??)
ассемблер состоит из двух частей: мнемокодов команд и операций ассемблера (терминология моя). мнемокод - это символьный аналог команды ALU, например, mov, ldi или rol. разумеется, последний мнемокод означает "сдвиг влево", т.к. вроде бы является аналогом оператора Си <<, и это на самом деле так. но есть еще операция языка ассемблера <<, которая означает ровно то же самое, но выполняется ассемблером на этапе компиляции. то есть не ALU микроконтроллера делает этот сдвиг, а сам ассемблер все двигает, подставляя в команду уже готовый результат этих сдвигов. улавливаете разницу?
rol r3, 4 в этом случае полностью эквивалентно rol r3, 1<<2, т.к. 1<<2 это и будет 4. таким образом, во время написания программы вы пользуетесь удобными вам константами, компилятор ассемблера делает необходимые вычисления сам, и подставляет в мнемокоды уже готовые числа.
итак, разница в операторе << языка Си и ассемблера в том, что в Си этот оператор может выполняться либо на этапе компиляции (макросы), либо на этапе исполненияя программы, а в ассемблере этот оператор всегда выполняется на этапе компиляции. и, естественно, оба операнда этого оператора должны быть константами, иначе компилятор не сможет выполнить эту работу - попробуйте написать что-то типа ldi r17, 1<<r6 - получите ошибку компиляции.
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей.
У АВРок системой команд официально не предусматривается прямое указание в команде количества сдвигов в случае с командами циклического сдвига / вращения (ROL\ROR и подобное). Это преимущество только за системой команд 8088/8086 и выше (и то, там еще регистр-счетчик вроде задействуется, ежли шклерозь не изменяет...). Конструкция rol rn,x скорее всего должна быть заменена препроцессором на цепочку из х команд rol rn, воспринимаемых самим МК... (если вообще будет пропущена компилятором - сам так "заворачивать" не пробовал)...
Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре.
Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств.
COKPOWEHEU пишет "Полностью аналогичен x = x*2^y не совсем понятно аналогичен чему. Насколько я понимаю х умножается на 2, а затем проводится "исключающее или" между произведением и "у" , но это опять операторы СИ
^ в смысле возведение в степень а не XOR.
WiseLord писал(а):
Ну.. на побитовое И он тоже не особо был похож
Да, что-то я там совсем странное написал... хотя бы исправленная версия нормально?
sibiryak69 писал(а):
на сколько я знаю в ассемблере AVR нет таких операторов "<<" и "|" там они пишутся по другому и компилятор эти начертания по логике не должен понять (или я не прав??)
ARV уже ответил, но продублирую. Сборка программы состоит из 2-х этапов: препроцессирование и компиляция (вообще-то есть еще линковка, но родной AVR ассемблер этого напрямую не умеет). На первом этапе препроцессор анализирует текст программы, не глядя на синтаксис целевого языка и обрабатывая только свои конструкции. Например, подставляет макросы прямо в текст программы, заменяет .def и .equ на соответствующие значения, подставляет вместо .include содержимое файла, и так далее. Примерно таким образом:
ldi r16,0b00000100;основание системы счисления я оставил наиболее наглядным, компилятору-то без разницы out 0x18, r16
Точно также Си-подобные операторы |, &, << и т.п. относятся к препроцессору и выполняются перед запуском компилятора, которому в результате достаются готовые вычисленные константы и адреса.
Все записи полностью идентичны, но первая гораздо понятнее, чем "магическое" число в последней.
не совсем понятно для чего в выше приведенном выражении использовать название разрядов регистра управления и что под этими названиями в данном случае подразумевается или номер разряда или содержимое разряда. Если номер разряда, то смысл в написании названия пропадает, и для меня более понятной будет последняя запись (все как говорится на месте, в регистр записывается конкретная константа) Если под названием разряда подразумевается его содержимое то это уже не константа.
на сколько я знаю в ассемблере AVR нет таких операторов "<<" и "|" там они пишутся по другому и компилятор эти начертания по логике не должен понять (или я не прав??)
ассемблер состоит из двух частей: мнемокодов команд и операций ассемблера (терминология моя). мнемокод - это символьный аналог команды ALU, например, mov, ldi или rol. разумеется, последний мнемокод означает "сдвиг влево", т.к. вроде бы является аналогом оператора Си <<, и это на самом деле так. но есть еще операция языка ассемблера <<, которая означает ровно то же самое, но выполняется ассемблером на этапе компиляции. то есть не ALU микроконтроллера делает этот сдвиг, а сам ассемблер все двигает, подставляя в команду уже готовый результат этих сдвигов. улавливаете разницу?
rol r3, 4 в этом случае полностью эквивалентно rol r3, 1<<2, т.к. 1<<2 это и будет 4. таким образом, во время написания программы вы пользуетесь удобными вам константами, компилятор ассемблера делает необходимые вычисления сам, и подставляет в мнемокоды уже готовые числа.
итак, разница в операторе << языка Си и ассемблера в том, что в Си этот оператор может выполняться либо на этапе компиляции (макросы), либо на этапе исполненияя программы, а в ассемблере этот оператор всегда выполняется на этапе компиляции. и, естественно, оба операнда этого оператора должны быть константами, иначе компилятор не сможет выполнить эту работу - попробуйте написать что-то типа ldi r17, 1<<r6 - получите ошибку компиляции.
Насколько я знаю в ассемблере есть два вида команд. 1 Как выше указал "ARV" мнемокод. Мнемокод по терминологии называется оператором 2 Второй вид команд это "дерективы". как выше указал ARV "дерективы" выполняются компилятором (как в языках программирования высокого уровня тот же "СИ") , примеры приводить не буду "COKPOWEHEU" привел хороший пример
но я такой команды "дерективы" как << в AVR не видел Если я не прав пожалуйста растолкуйте
Всем доброго времени суток. Возможно немного не в тему, но.. Возникла у меня недавно необходимость деления целых чисел. Исшарил много интернетов, но внятного, а тем более однозначного куска кода или алгоритма не нашел (может просто плохо искал, не спорю, но искал именно на Ассемблер). Так вот, не найдя ничего готового сел изобретать велосипед. Привожу два своих варианта алгоритмов на общественный суд, ну и может кому пригодится. (тема по конкретно этому вопросу закрыта и не доведена до лог завершения). Итак: 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
2й занимает больше места, но выполняется немного быстрей и более стабилен по времени + правильней с точки зрения двоичной математики:
Спойлер; .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 Ну вот, высказался. Вроде легче стало
_________________ Если я чего-то не знаю, это не говорит о моем невежестве, а только о том, что раньше этот вопрос лежал вне сферы моих интересов.
Все записи полностью идентичны, но первая гораздо понятнее, чем "магическое" число в последней.
не совсем понятно для чего в выше приведенном выражении использовать название разрядов регистра управления и что под этими названиями в данном случае подразумевается или номер разряда или содержимое разряда. Если номер разряда, то смысл в написании названия пропадает, и для меня более понятной будет последняя запись (все как говорится на месте, в регистр записывается конкретная константа) Если под названием разряда подразумевается его содержимое то это уже не константа.
Ещё раз - это номера битов, ровно как они указаны в даташите. И при использовании первого варианта сразу понятно, что в регистр записывается байт, у которого установлены эти биты.
Последний вариант - магическое число, непонятно откуда взявшееся в программе. Понять, почему использовано именно это число невозможно, не заглядывая дальше по коду. Нужно обязательно смотреть, в какой регистр этот 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 - это гораздо быстрее ряда вычитаний, да и выполняется это за константное время.
Если правильно понял два последних алгоритма, то в них пренебрегаем остатком после деления, принимая во внимание только целую часть (может конечно и ошибаюсь). В некоторых случаях это критично. К примеру в моем случае нужно сначала 1440 (2 рег) / 24 получаем на выходе 2 рег ответа (целое и остаток), после этого каждый из них разделить на 10 (привести в знаки индикатора). То есть остаток имеет довольно важное значение.
_________________ Если я чего-то не знаю, это не говорит о моем невежестве, а только о том, что раньше этот вопрос лежал вне сферы моих интересов.
Ну, так никто не мешает после получения результата (целого частного) быстро вычислить и остаток. N / 24 = X, в остатке Y. В вашем случае Вы путём долгих вычислений получаете сразу оба числа. Но ведь если X получен быстрым способом, то уже не проблема так же быстро получить: Y = N - 24*X;
WiseLord спасибо за объяснение. Если я правильно понял, данный вид записи (ldi r16, (1<<USIWMO)|(1<<USICS1)|(1<<USICLK)|(1<<USITC)) универсален тем, что в разных МК биты с одним названием могут находиться в разных разрядах, и при переносе с одного МК на другой, компилятор сам вычислит число необходимое для выставления нужных разрядов, а программисту не надо парится
В обработчике запустили таймер или сделали отсечку уже запущенного таймера. Ждете отпускания кнопки и в обработчике сделали следующую отсечку. Разница покажет длительность нажатия на кнопку.
Здравствуйте, начал изучать ассемблер AVR. Интересует такой момент, как с помощью внешнего прерывания улавливать длинное и короткое нажатие на кнопку?
1 - Подключение кнопок к внешнему прерыванию требуется только в единственном случае - если устройству требуется энергосбережение. 2 - Кнопки - человеко-интерфейс. Это значит, что вам не нужна реакция в нано, микро и даже миллисекунды. 3 - У кнопок есть дребезг контактов (спросить у гугла).
Есть цикл статей Татарчевского. Там отлично расписано, как сделать опрос кнопок. Пусть си вас не смущает. Главное понять алгоритм.
Добавлено after 1 minute 19 seconds: Re: Ассемблер (ASM) для AVR в вопросах и ответах
В обработчике запустили таймер или сделали отсечку уже запущенного таймера. Ждете отпускания кнопки и в обработчике сделали следующую отсечку. Разница покажет длительность нажатия на кнопку.
Пусть он сразу ознакомится, что такое программные таймеры. И автоматное программирование.
... как с помощью внешнего прерывания улавливать длинное и короткое нажатие на кнопку?
может radio-fan вырос из программных таймеров и переходит на более высокий уровень, задействуя аппаратную периферию и прерывания от оной для опроса кнопок в фоновом режиме.
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 46
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения