В R0 грузится не адрес а содержимое байта памяти по адресу, который содержится в ZH:ZL
Вот это я протупил !!! Теперь все встало на свои места. И написано же "Загружает один байт, адресованный регистром Z, в регистр 0 (R0)..." Спасибо огромное, можно ехать дальше.
_________________ "Слишком много людей ломаются, даже не подозревая о том, насколько близки к успеху они были в тот момент, когда упали духом". Томас Алва Эдисон
Про множитель понятно, и про загрузку в регистровую пару тоже. Адрес ПЗУ 16-ти битный, так? И все это в пару грузится нормально (два регистра). А вот как этот адрес в R0 загружается я не понимаю.
В r0 загружается не адрес слова в ПЗУ, а значение этого слова, а точнее полуслова. Рассказываю
Когда вы грузите в пару Z адрес слова в ПЗУ, умноженный на 2, то младший бит получившегося числа будет равен 0, значит в r0 считывается значение младшего байта слова по адресу(здесь уже считайте что адрес не умножен на 2), загруженному в Z. Когда младший бит числа, соответсвующего адресу, будет равен 1, то в r0 загрузится старший байт слова.
Мое объяснение несколько сумбурно, лучше всего Вы найдите на сайте атмел документ AVR Instruction Set и в почитайте, там в начале расписаны все способы адресации с картинками, на мой взгляд очень доходчиво, после этого почитайте описание команды lpm, тогда думаю вообще неясностей не останется.
Попробую на всякий случай по-другому объяснить (для лучшего понимания см присоединенный рисунок):
пятнадцать старших бит, загруженных в Z определяют адрес по которому в r0 будет загружаться младший или старший байт слова, расположенного в памяти программ по этому адресу. Младший байт слова загружается в r0, если младший бит в Z равен 0, старший байт - если младший бит в Z равен 1.
В r0 загружается не адрес слова в ПЗУ, а значение этого слова, а точнее полуслова. Рассказываю Когда вы грузите в пару Z адрес слова в ПЗУ, умноженный на 2, то младший бит получившегося числа будет равен 0, значит в r0 считывается значение младшего байта слова по адресу(здесь уже считайте что адрес не умножен на 2), загруженному в Z. Когда младший бит числа, соответсвующего адресу, будет равен 1, то в r0 загрузится старший байт слова.
И Вам спасибо огромное. Разумеется я перед тем как спросить проштудировал информацию про адресацию. И про то что младший значащий разряд указателя выбирает младший или старший байт слова тоже. Просто на адресе зациклился и завис... Теперь вопросов по-этому поводу нет, можно двигаться дальше.
_________________ "Слишком много людей ломаются, даже не подозревая о том, насколько близки к успеху они были в тот момент, когда упали духом". Томас Алва Эдисон
Разобравшись с переключением массивов по прерыванию reset решил добить проект бегущих огней до простенького автомата световых эффектов (пока без ШИМ). На внешние прерывания МК Attiny2313 повесил две кнопки (выбор режима и изменение скорости). С настройкой внешних прерываний вроде проблем не возникло, все заработало сразу. Правда возникли неясности. GIMSK я собственно разрешил внешние прерывания а MCUCR настроил на работу по низкому уровню. Теперь вопросы:
1. Осталось непонятным PCIE в GIMSK. Вроде как разрешение прерывания по изменению состояния выводов. Когда оно используется я не понимаю. При чем пишут что прерывание возникает при ЛЮБОМ изменении сигнала на ЛЮБОМ входе.
2. Та же история с флагами прерываний EIFR
3. Даже не вопрос а скорее небольшая просьба. Я прикрепил исходник этих огней, не могли бы вы посмотреть на предмет замечаний. Структура программы, может какие-то ошибки... Не хотелось бы с самого начала эти ошибки допускать.
4. И там же. Не могли бы вы натолкнуть на мысль, каким образом можно реализовать изменение скорости выполнения эффектов. По кольцу одной кнопкой.
Заранее благодарен.
_________________ "Слишком много людей ломаются, даже не подозревая о том, насколько близки к успеху они были в тот момент, когда упали духом". Томас Алва Эдисон
Карма: 2
Рейтинг сообщений: 11
Зарегистрирован: Пт май 23, 2008 19:32:22 Сообщений: 2401 Откуда: Россия, Волгоград
Рейтинг сообщения:0 Медали: 1
использовать массивы для бегущих огней - это круто, гораздо проще реализовать на командах циклического сдвига, а обработку сдвига производить по прерыванию таймера.
добавте переменную которую будете увеличивать/уменьшать (без разницы) от мин до макс (или от макс до мин) значения при нажатии на кнопку, это будет коэф.пересчета дальше делайте с ним что хотите
_________________ Чем дальше, тем больше становлюсь занудой...
использовать массивы для бегущих огней - это круто, гораздо проще реализовать на командах циклического сдвига, а обработку сдвига производить по прерыванию таймера. добавте переменную которую будете увеличивать/уменьшать (без разницы) от мин до макс (или от макс до мин) значения при нажатии на кнопку, это будет коэф.пересчета дальше делайте с ним что хотите
Из обучалки так пошло. Там ведь несколько эффектов, и я так думаю что массивами удобнее гораздо. LSL и LSR были когда был один бегущий огонь. Да и постарайтесь понять, я же недавно начал изучать ассемблер, и мне же лучше использовать все что можно.
А обработка сдвига и так по прерыванию таймера происходит. Можно увеличивать переменную и затем грузить ее в компаратор? Или проще можно?
_________________ "Слишком много людей ломаются, даже не подозревая о том, насколько близки к успеху они были в тот момент, когда упали духом". Томас Алва Эдисон
Последний раз редактировалось edm2007 Пт май 08, 2009 23:07:38, всего редактировалось 1 раз.
Карма: 2
Рейтинг сообщений: 11
Зарегистрирован: Пт май 23, 2008 19:32:22 Сообщений: 2401 Откуда: Россия, Волгоград
Рейтинг сообщения:0 Медали: 1
Собственно я не вижу смысла в применении компаратора, для чего он здесь вообще, у вас же нет отслеживания какой-то аналоговой величины на входе или я не прав?
переменную можно использовать для изменения коэф.пересчета основного счетчика, определяющего время переключения между каналами.
зы: для изучения работы с массивами согласен.
_________________ Чем дальше, тем больше становлюсь занудой...
Собственно я не вижу смысла в применении компаратора, для чего он здесь вообще, у вас же нет отслеживания какой-то аналоговой величины на входе или я не прав? переменную можно использовать для изменения коэф.пересчета основного счетчика, определяющего время переключения между каналами. зы: для изучения работы с массивами согласен.
Так не про аналоговой компаратор речь. Просто прерывание по совпадению. Я на самом деле не понимаю про коэф. пересчета.
_________________ "Слишком много людей ломаются, даже не подозревая о том, насколько близки к успеху они были в тот момент, когда упали духом". Томас Алва Эдисон
Зарегистрирован: Вс янв 07, 2007 01:45:48 Сообщений: 491 Откуда: Российская Федерация, будь она неладна...
Рейтинг сообщения:0
Цитата:
А вот как этот адрес в R0 загружается я не понимаю.
А по чему, если не секрет, это Вас так интересует? Ну грузится, и слава Богу
_________________ Научить нельзя, можно научиться. Пифагор. Вставь недостающие буквы в слово *у*ня. Если у тебя получилось слово кухня, значит ты интеллигентный человек.
А вот как этот адрес в R0 загружается я не понимаю.
А по чему, если не секрет, это Вас так интересует? Ну грузится, и слава Богу
Такой уж я человек. Если что-то изучаю, то стараюсь это делать осмысленно и досконально. Предела совершенству нет, но стремиться к нему все же стоит. Я, собственно, асм и стал изучать для того чтобы понять что вообще происходит в голове у МК. А если "слава Богу" так я и на бейсике напишу, пусть он сам разбирается куда и что помещать. Впрочем, все это всего лишь мое скромное мнение...
_________________ "Слишком много людей ломаются, даже не подозревая о том, насколько близки к успеху они были в тот момент, когда упали духом". Томас Алва Эдисон
Доброго времени суток!
Дамы и Господа !
Обьясните новичку, почему в блоке «Переключение светодиода» в первой строчке PINB а не PORTB? Ведь порт Б настроен на вывод
И …
Для каких целей в блоке «подпрограмма задержки» сохраняем в стек, а потом извлекаем из стека содержимое регистра loop ??? я так понимаю во время этой операции он вообще пустой, то есть забит нулями. Операция декремента, как я понимаю, производится не над содержимым стека ? а над реальным содержимым регистра
Бред имхо …
.cseg ; Выбор сегмента программного кода
.org 0 ; Устанеовка текущего адреса на ноль
.def temp = r16 ; Определение главного рабочего регистра
.def loop = r17 ; Определение регистра организации цикла
;---------- Инициализация стека
ldi temp, 0x7F ; Выбор адреса вершины стека
out SPL, temp ; Запись его в регистр стека
;---------- Инициализация Главного предделителя
ldi temp, 0x80 ; Записываем число $80 в регистр temp
out CLKPR, temp ; Записываем в регистр CLKPR
ldi temp, 0 ; Записываем 0 в регистр temp
out CLKPR, temp ; Записываем этот ноль в CLKPR
;---------- Инициализация портов ВВ
out DDRD, temp ; Записываем этот ноль в DDRD (порт PD на ввод)
ldi temp, 0xFF ; Записываем число $FF в регистр temp
out DDRB, temp ; Записываем это число в DDRB (порт PB на вывод)
out PORTB, temp ; Записываем то же число в PORTB (потушить светодиод)
out PORTD, temp ; Записываем его же в PORTD (включаем внутр. резисторы)
;---------- Инициализация компаратора
ldi temp, 0x80 ; Выключение компаратора
out ACSR, temp
;---------- Начало основного цикла
main:
in temp, PIND ; Читаем содержимое порта PD
sbrc temp, 0 ; Проверка младшего разряда
rjmp main ; Если не ноль, переходим в начало
rcall wait ; Вызов подпрограммы задержки
;---------- Переключение светодиода
in temp, PINB ; Читаем содержимое порта PB
sbrc temp, 0 ; Проверка младшего разряда
rjmp m1
sbi PORTB, 0 ; Установка выход PB0 в единицу
rjmp m2
m1: cbi PORTB, 0 ; Сброс PB0 в ноль
;---------- Цикл ожидания отпускания кнопки
m2: in temp, PIND ; Читаем содержимое порта PD
sbrs temp, 0 ; Проверка младшего разряда
rjmp m2 ; Продолжить ожидание отпускания кнопки
rcall wait ; Вызов подпрограммы задержки
rjmp main ; К началу цикла
;---------- Подпрограмма задержки
wait: push loop ; Сохраняем содержимое регистра loop
ldi loop, 200 ; Помещаем в loop константу задержки
; Цикл задержки
wt1: dec loop ; Уменьшаем значение регистра loop
brne wt1 ; Если не ноль, продолжаем цикл
pop loop ; Восстанавливаем значение регистра loop
ret ; Выход из подпрограммы
Доброго времени суток! Дамы и Господа ! Обьясните новичку, почему в блоке «Переключение светодиода» в первой строчке PINB а не PORTB? Ведь порт Б настроен на вывод И … Для каких целей в блоке «подпрограмма задержки» сохраняем в стек, а потом извлекаем из стека содержимое регистра loop ???
Привет. Так все правильно, мы сначала загружаем содержимое порта B в temp, а потом командой sbrc проверяем младший разряд порта (куда подключен светодиод). Нам же нужно знать, горит он в данный момент или нет. Команда sbrc вызывает пропуск следующей за ней команды, если проверяемый регистр РОН сброшен (0). У команды два параметра, имя регистра общего назначения, и номер проверяемого бита. Вот мы и проверяем младший разряд. Если он равен нулю (я не знаю как светодиод подключен, ну допустим он не горит), мы пропускаем команду rjmp m1 а сразу переходим к установке 1 в порт B0 (зажигаем светодиод), если же он не равен нулю (светодиод горит), команду rjmp m1 не пропускаем, и переходим к сбросу порта B0 (гасим светодиод). Таким образом в зависимости от того что имеется на порту к которому подключен светодиод мы принимаем решение как действовать дальше. Либо менять 0 на 1, либо 1 на 0.
А по-поводу стека... В данном случае оно смысла не имеет, хотя подобная процедура - штука полезная. Ибо по окончанию подпрограммы задержки, значения всех регистров МК остаются без изменений. Полезно тогда, когда та же переменная используется в основном цикле. Какую взяли - такую и вернули.
Запутал наверное еще больше, но вроде так... Я сам недавно начал изучать asm, так что сильно не бейте.
_________________ "Слишком много людей ломаются, даже не подозревая о том, насколько близки к успеху они были в тот момент, когда упали духом". Томас Алва Эдисон
Карма: 2
Рейтинг сообщений: 11
Зарегистрирован: Пт май 23, 2008 19:32:22 Сообщений: 2401 Откуда: Россия, Волгоград
Рейтинг сообщения:0 Медали: 1
to MeL$ ИМХО
Некоторые замечания по оформлению текста программы,
для данной программы это не существенно, но когда перейдете к более менее серьезным проектам дурная привычка скажется.
- описывайте переменные до кодового сегмента
- оставляйте место под вектора прерываний, только в простейших примерах не используются разлиные прервания :
Код:
.org 0 jmp(или rjmp для младших процессоров) start ... (таблица векторов прерываний) ... start: ; начало основной программы
- пользуйтесть опредлениями из файла хххххdef.inc. так для верхней границы ОЗУ лучше использовать "RAMEND"
Код:
ldi temp,low(RAMEND) out SPL,temp
меньше вариантов допустить ошибку - сохраняйте в стеке регистры используемые для промежуточных операций в подпрограммах, поверьте эта привычка съэкономит кучу времени и нервов, не надо будет искать - почему это программа выдает "цену на дрова в прошлом году" вместо того что надо
В общем не наступайте на грабли по которым уже прошлись другие, приучите себя сразу писать "красиво", ведь "красота спасет мир" (и программистов )
_________________ Чем дальше, тем больше становлюсь занудой...
А вот мне, к сожалению, никто помочь не хочет. Не могу я понять как изменить скорость бегущих огней. Задержка между переключением светодиодов через прерывание таймера по совпадению. Ну введу я переменную скорости, буду ее в обработчике прерывания увеличивать / уменьшать, а вот как все это в компаратор записать я не соображу никак.
_________________ "Слишком много людей ломаются, даже не подозревая о том, насколько близки к успеху они были в тот момент, когда упали духом". Томас Алва Эдисон
Карма: 2
Рейтинг сообщений: 11
Зарегистрирован: Пт май 23, 2008 19:32:22 Сообщений: 2401 Откуда: Россия, Волгоград
Рейтинг сообщения:0 Медали: 1
У вас же есть строки:
Код:
ldi temp, 0x3d ; инициализация компаратора (загружаем число, с которым сравниваем таймер) out ocr1ah, temp ldi temp, 0x09 out ocr1al, temp
Это и есть загрузка компаратора таймера
ИМХО я бы сделал так:
1. организал бы счетчик Т1 на формирование какого-нибудь определенного промежутка времени
2. с помощью клавы изменял коеэф. пересчета кратный заданным интервалам Т1 (не забывать при вводе коэф блокировать Т1 а то получится бред)
3. по каждому "сбросу по совпадению" Т1 уменьшал коэф на 1, пока не станет равным нулю
4. изменяем состояние порта управления светиками
5. восстанавливаем значение коэф.
6. переход на п.3 и так по кругу.
_________________ Чем дальше, тем больше становлюсь занудой...
Доброго времени суток! Дамы и Господа ! Обьясните новичку, почему в блоке «Переключение светодиода» в первой строчке PINB а не PORTB? Ведь порт Б настроен на вывод И … Для каких целей в блоке «подпрограмма задержки» сохраняем в стек, а потом извлекаем из стека содержимое регистра loop ???
Привет. Так все правильно, мы сначала загружаем содержимое порта B в temp, а потом командой sbrc проверяем младший разряд порта (куда подключен светодиод). Нам же нужно знать, горит он в данный момент или нет. Команда sbrc вызывает пропуск следующей за ней команды, если проверяемый регистр РОН сброшен (0). У команды два параметра, имя регистра общего назначения, и номер проверяемого бита. Вот мы и проверяем младший разряд. Если он равен нулю (я не знаю как светодиод подключен, ну допустим он не горит), мы пропускаем команду rjmp m1 а сразу переходим к установке 1 в порт B0 (зажигаем светодиод), если же он не равен нулю (светодиод горит), команду rjmp m1 не пропускаем, и переходим к сбросу порта B0 (гасим светодиод). Таким образом в зависимости от того что имеется на порту к которому подключен светодиод мы принимаем решение как действовать дальше. Либо менять 0 на 1, либо 1 на 0.
А по-поводу стека... В данном случае оно смысла не имеет, хотя подобная процедура - штука полезная. Ибо по окончанию подпрограммы задержки, значения всех регистров МК остаются без изменений. Полезно тогда, когда та же переменная используется в основном цикле. Какую взяли - такую и вернули.
Запутал наверное еще больше, но вроде так... Я сам недавно начал изучать asm, так что сильно не бейте.
ага всем спасибо за ответы/советы, но наверное вопрос не поняли (((
или я его непонятно сформулировал ...
меня интересует почему используется именно PINB , а не PORTB ???
мы же для порта Б ddr установили, тоесть порт Б работает на вывод
почему тогда используется PINB
ведь PINB - это ввод , а у нас вывод
имхо ...
ту GP1
по культуре оформления программы замечания учту - спасибо!
просто я пока только начинаю заниматься и всех тонкостей просто не понимаю ...
ага всем спасибо за ответы/советы, но наверное вопрос не поняли ((( или я его непонятно сформулировал ... меня интересует почему используется именно PINB , а не PORTB ??? мы же для порта Б ddr установили, тоесть порт Б работает на вывод почему тогда используется PINB ведь PINB - это ввод , а у нас вывод имхо ...
ту GP1 по культуре оформления программы замечания учту - спасибо! просто я пока только начинаю заниматься и всех тонкостей просто не понимаю ...
Потому что PORTB не соединен электрически внутри МК со схемой входа, он может работать только в режиме «выход».
Если необходимо считать состояние вывода порта, то это надо делать из PINB, так как именно через него осуществляется считывание данных в МК.
_________________ "Слишком много людей ломаются, даже не подозревая о том, насколько близки к успеху они были в тот момент, когда упали духом". Томас Алва Эдисон
Карма: 1
Рейтинг сообщений: 3
Зарегистрирован: Пн сен 01, 2008 14:49:03 Сообщений: 151 Откуда: Казахстан
Рейтинг сообщения:0
MeL$, PORTB доступен и для записи, и для чтения, так же как и PINB. Но при чтении с PINB мы получим реальное состояние на ноге порта, а при чтении PORTB то значение, которое записано в этот регистр. И в общем случае эти значения не обязаны совпадать - например во время переходных процессов, или когда нагрузка на ногу слишком большая. Всё это сказано к случаю, когда порт настроен на вывод, т.е. в DDRB записаны единицы. Я к сожалению, плохо объясняю, посмотри на схему вывода порта по даташиту или в книжке какой, - и всё будет ясно.
ps: кстати в данной программе правильней будет читать всё-таки с PORTB, а не с PINB.
ps2: И вообще, что бы проверить состояние одного бита порта, совсем не обязательно его читать полностью. Для этого есть команды sbic, sbis.
Код:
;---------- Переключение светодиода
sbic PORTB, 0 ; Проверка младшего разряда rjmp m1 sbi PORTB, 0 ; Установка выход PB0 в единицу rjmp m2 m1: cbi PORTB, 0 ; Сброс PB0 в ноль
ps3: Да, а если бы МК был класса Мега, то было бы ещё проще:
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 298
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения